I am working with v4 gulp and converting my tasks to functions. I have a simple clean function that executes a parallel task.
const clean_server = () => del('build/server/*');
const clean_client = () => del('build/client/*');
export function clean(done) {
gulp.parallel(clean_server, clean_client);
done();
}
When I call done() the way I'm calling above, which is also suggested from the docs https://gulpjs.com/docs/en/getting-started/creating-tasks, I see the task get initiated, however, it doesn't actually complete the task.
However, when I change it to:
export function clean(done) {
gulp.parallel(clean_server, clean_client)(done);
}
This way works.
So my question is, why doesn't the first way as suggested by the docs complete the async task?
Because done must be passed as a callback to parallel. Either like the way you did on or like the following
gulp.parallel(done => {
clean_server()
clean_client();
done();
})
Related
I have an function called translateCommand(command) that uses a Translate package from npm to translate some text into a different language. The problem is the translate function provided by that package is asynchronous and it tends to exit the translateCommand function before the translate function is finished, resulting in the return of garbage data.
I identified it finishing too fast as the issue and made translateCommand(command) an async function, so that I could use await in front of the imported translate() function, which solved that issue, but now I've simply delayed the issue a step further back because the function that calls translateCommand(command) is experiencing the exact same issue and I feel like I've made no headway if I'm just going to have to keep repeating this chain upward.
Fact of the matter is, I don't really understand Promises and how Async functions behave in general in relation to them. I realize this is a premise that makes Node.js great, but trying to learn about it has been fairly ineffective. Trying to solve this problem hasn't really bore fruit as everyone just says to use callback without explaining what exactly a callback is. It doesn't help that the examples were usually surrounded with unfamiliar code, so I figured getting help in the context of my code would tackle two birds with one stone.
This whole process is my introductory attempt to make a silly Discord Bot where I've implemented a bunch of silly features. I've ran into the Async wall many times, but usually found a Synchronous alternative to proceed forward. This time I did not, and I've tried to emulate callbacks described in other Stack Overflow posts, but due to a lack of understanding, was unable to integrate them correctly (I can only assume).
Top-level imported function that now has the Async issue.
client.on("message", (message) => {
// ...
let command = (message.content).substr(1);
// ...
// Handles translate command
else if (command.startsWith("translate"))
message.channel.send(translateCommand(command));
// ...
}
});
Function that was made async so it could await:
// Form !translate [string]
async function translateCommand(command) {
let message = "";
let str = command.substr(10);
await translate(str, { to: 'ja', engine: 'yandex', key: '<my key>' }).then(function(result) {
message = result;
return "";
});
return message;
}
I'm aware this question has been asked to death, but I feel that without context I understand (as I'm still new to both JS and Node), I can only proceed by beating my head against a wall until something works without me understanding why.
You can change your top-level function to be async as well. Change the beginning to async (message) => { and use message.channel.send(await translateCommand(command)). Alternatively, you could opt to use promises and not make the function async, and instead use translateCommand(command).then(msg => message.channel.send(msg)), however it could mess up the flow later in the code.
Because translate returns a promise you don't need to make translateCommand async. Simply return translate from the function...
function translateCommand(command) {
let str = command.substr(10);
return translate(str, { to: 'ja', engine: 'yandex', key: '<my key>' });
}
...and await the promise to resolve. You need to add async to the event handler callback for await to work.
client.on("message", async (message) => {
let command = (message.content).substr(1);
//...
else if (command.startsWith("translate"))
message.channel.send(await translateCommand(command));
// ...
}
});
Using promises, you could do the following:
translateCommand function:
var translateCommand = (command) => new Promise((resolve,reject) => {
translate(command.substr(10), { to: 'ja', engine: 'yandex', key: '<my key>' })
.then(resolve)
.catch(reject)
});
then client.on:
client.on("message", (message) => {
// ...
let command = (message.content).substr(1);
// ...
// Handles translate command
else if (command.startsWith("translate"))
translateCommand(command)
.then(translationResult => {
message.channel.send(translationResult)
})
// ...
}
});
If you have troubles with the syntax, here are the hints:
hint #1
hint #2
+ One remark - don't be afraid and take your time to read + implement the above examples and modify them afterwards to cause errors (you will know how and when they do or do not work - painful but rewarding ;) )
I need to execute an argument that is a callback of a jest mock.
In the jest documentation, their callback example is about testing the first callback. I have behaviors inside nested callbacks I need to test. In the examples of promises, they use resolves and rejects. Is there anything like this for nested callbacks? I'm currently executing the mocked call argument, which I'm not sure if it is the recommended way.
System under test:
function execute() {
globals.request.post({}, (err, body) => {
// other testable behaviors here.
globals.doSomething(body);
// more testable behaviors here. that may include more calls to request.post()
});
}
The test:
globals.request.post = jest.fn();
globals.doSomething = jest.fn();
execute();
// Is this the right way to execute the argument?
globals.request.post.mock.calls[0][1](null, bodyToAssertAgainst);
expect(globals.doSomething.mock.calls[0][1]).toBe(bodyToAssertAgainst);
My question is in the comments in the code above. Is this the recommended way to execute a callback, which is an argument of the mocked function?
Since you don't care about the implementation of your globals.request.post method you need to extend your mock a bit in order for your test to work.
const bodyToAssertAgainst = {};
globals.request.post = jest.fn().mockImplementation((obj, cb) => {
cb(null, bodyToAssertAgainst);
});
Then you can go onto expect that doSomething was called with bodyToAssertAgainst. Also, this way you can easily test if your post would throw an Error.
I had a function that did three different tasks, which worked fine. For better re-usability I tried to separate them into three independent hooks.
They look like this:
module.exports = function(options = {}) {
return function hookFunction(hook) {
//do stuff and set variables
function(hook.params.var){ ... } // only in second and third
hook.params.var = var; // only in first and second
return Promise.resolve(hook);
};
};
My service.hook file contains this:
module.exports = {
before: {
find: [ firstHook(), secondHook(), thirdHook() ]}}
Now they seem to run simultaneously, which causes the third to throw an error caused by missing data from first and second. I want them to run one after another. How could I achieve that?
(I tried to use .then in service.hook but it throws TypeError: hookFunction(...).then is not a function.)
I've read How to run synchronous hooks on feathersjs but I don't quite know where to place the chaining - in the third hook or in the service hook or elsewhere?
Hooks will run in the order they are registered and if they return a promise (or are an async function) it will wait for that promise to resolve. The most common mistake if they run at once but should run in sequence is that no promise or the wrong promise is being returned but it is not clear from your code example if that is the case. The following example will work and wait one second each, then print the current name and move to the next:
function makeHook(name) {
return function(context) {
return new Promise(resolve => {
setTimeout(() => {
console.log(`Running ${name}`);
resolve(context);
}, 1000);
});
}
}
module.exports = {
before: {
find: [ makeHook('first'), makeHook('second'), makeHook('third') ]}}
I'm trying to get the results from a mock backend in Angular 2 for unit testing. Currently, we are using fakeAsync with a timeout to simulate the passing of time.
current working unit test
it('timeout (fakeAsync/tick)', fakeAsync(() => {
counter.getTimeout();
tick(3000); //manually specify the waiting time
}));
But, this means that we are limited to a manually defined timeout. Not when the async task is completed. What I'm trying to do is getting tick() to wait until the task is completed before continuing with the test.
This does not seem to work as intended.
Reading up on the fakeAsync and tick the answer here explains that:
tick() simulates the asynchronous passage of time.
I set up a plnkr example simulating this scenario.
Here, we call the getTimeout() method which calls an internal async task that has a timeout. In the test, we try wrapping it and calling tick() after calling the getTimeout() method.
counter.ts
getTimeout() {
setTimeout(() => {
console.log('timeout')
},3000)
}
counter.specs.ts
it('timeout (fakeAsync/tick)', fakeAsync(() => {
counter.getTimeout();
tick();
}));
But, the unit test fails with the error "Error: 1 timer(s) still in the queue."
Does the issue here in the angular repo have anything to do with this?
Is it possible to use tick() this way to wait for a timeout function? Or is there another approach that I can use?
The purpose of fakeAsync is to control time within your spec. tick will not wait for any time as it is a synchronous function used to simulate the passage of time. If you want to wait until the asynchronous function is complete, you are going to need to use async and whenStable, however, in your example, the spec will take 3 seconds to pass so I wouldn't advise this.
The reason why the counter.spec.ts is failing is that you have only simulated the passage of 0 seconds (typically used to represent the next tick of the event loop). So when the spec completes, there are still mocked timers active and that fails the whole spec. It is actually working properly by informing you that a timeout has been mocked an is unhandled.
Basically, I think you are attempting to use fakeAsync and tick in ways for which they were not intended to be used. If you need to test a timeout the way that you have proposed, the simplest way would be to mock the setTimeout function yourself so that, regardless of the time used, you can just call the method.
EDITED
I ran into a related issue where I wanted to clear the timers, and since it was not the part under test, I didn't care how long it took. I tried:
tick(Infinity);
Which worked, but was super hacky. I ended up going with
discardPeriodicTasks();
And all of my timers were cleared.
Try to add one or a combination of the following function calls to the end of your test:
flush();
flushMicrotasks();
discardPeriodicTasks();
or try to "kill" the pending tasks like this:
Zone.current.get('FakeAsyncTestZoneSpec').pendingTimers = [];
Zone.current.get('FakeAsyncTestZoneSpec').pendingPeriodicTimers = [];
flush (with optional maxTurns parameter) also flushes macrotasks. (This function is not mentionned in the Angular testing tutorial.)
flushMicrotasks flushes the microtask queue.
discardPeriodicTasks cancels "periodic timer(s) still in the queue".
Clearing the pending (periodic) timers array in the current fake async zone is a way to avoid the error if nothing else helps.
Timers in the queue do not necessarily mean that there's a problem with your code. For example, components that observe the current time may introduce such timers. If you use such components from a foreign library, you might also consider to stub them instead of "chasing timers".
For further understanding you may look at the javascript code of the fakeAsync function in zone-testing.js.
At the end of each test add:
fixture.destroy();
flush();
Try this:
// I had to do this:
it('timeout (fakeAsync/tick)', (done) => {
fixture.whenStable().then(() => {
counter.getTimeout();
tick();
done();
});
});
Source
Async
test.service.ts
export class TestService {
getTimeout() {
setTimeout(() => { console.log("test") }, 3000);
}
}
test.service.spec.ts
import { TestBed, async } from '#angular/core/testing';
describe("TestService", () => {
let service: TestService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [TestService],
});
service = TestBed.get(TestService);
});
it("timeout test", async(() => {
service.getTimeout();
});
});
Fake Async
test.service.ts
export class TestService {
readonly WAIT_TIME = 3000;
getTimeout() {
setTimeout(() => { console.log("test") }, this.WAIT_TIME);
}
}
test.service.spec.ts
import { TestBed, fakeAsync } from '#angular/core/testing';
describe("TestService", () => {
let service: TestService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [TestService],
});
service = TestBed.get(TestService);
});
it("timeout test", fakeAsync(() => {
service.getTimeout();
tick(service.WAIT_TIME + 10);
});
});
I normally use the flushMicrotasks method in my unit tests for use with my services. I had read that tick() is very similar to flushMicrotasks but also calls the jasmine tick() method.
For me all above didnt helped, but a double call of tick(<async_time>) in my test code.
My explanation so far: for every async call you a need a single/own tick()-call.
I have a .pipe(debounceTime(500)) and a timer(500).subscribe(..) afterwards and this helped:
tick(500);
tick(500);
I'm striving to create a Gulp task that does nothing except calling a custom function. No, I have, no source files, and no, I have no destination files. I just want to call a custom function in a standalone task, so I can have other tasks depending on it.
For the love of me, I've checked Google and SO and I couldn't find an example. The closest I've come with is this
var through = require('through2');
gulp.task(
'my-custom-task',
function ()
{
return through.obj(
function write(chunk, enc, callback) {
// here is where the custom function is called
myCustomFunction('foo', 'bar');
callback(null, chunk);
}
);
}
);
Now this does call myCustomFunction, but when I run the task with gulp my-custom-task, I can see the task starting but not finishing.
[10:55:37] Starting 'clean:tmp'...
[10:55:37] Finished 'clean:tmp' after 46 ms
[10:55:37] Starting 'my-custom-task'...
How should I write my task correctly?
If you just want a task that runs some function, then just do that:
gulp.task('my-custom-task', function () {
myCustomFunction('foo', 'bar');
});
If your function does something asynchronously, it should call a callback at the end, so gulp is able to know when it’s done:
gulp.task('my-custom-task', function (callback) {
myCustomFunction('foo', 'bar', callback);
});
As for why your solution does not work, using through is a way to work with streams. You can use it to create handlers which you can .pipe() into gulp streams. Since you have nothing actually using gulp streams, there is no need for you to create a stream handler and/or use through here.