I first call
this.admobFree.interstitial.prepare()
.then(() => {
this.interstitialPrepared = true;
console.log('AdMob Interstitial Ad is prepared, will be presented if autoShow is true, otherwise, call showInterstitial().');
})
.catch((err) => {
console.error(err);
})
And this.interstitialPrepared = true; is called so I assume my ad is ready.
But if I call this.admobFree.interstitial.show() after my this.interstitialPrepared var switch to true, I still have the following error "ERROR: interstitial not ready yet.".
Notice :
It works well with the following config :
this.adMobProvider.interstitialConfig = {
autoShow: false,
isTesting : true
};
But not when I want to test with real ads
this.adMobProvider.interstitialConfig = {
autoShow: false,
isTesting : false,
id:"ca-app-pub-277368299xxxxxxxx"
};
I had the same problem and I did this way:
I did not put the interstitial.show() after interstitial.prepare().then(..);
I subscribed these events: INTERSTITIAL_LOAD and INTERSTITIAL_LOAD_FAIL;
I only showed it loaded successfully;
Example:
this.admobFree.on(this.admobFree.events.INTERSTITIAL_LOAD).subscribe(() => {
this.admobFree.interstitial.show().then(() => {
// Show successful
}).catch((errorShow) => {
// ...
});
});
this.admobFree.on(this.admobFree.events.INTERSTITIAL_LOAD_FAIL).subscribe(() => {
// ...
});
I hope to help you.
In my case autoShow: trueworked for me. Remember when autoShow is true you don't need to call the intersit
Related
I am trying to test AsyncTypeahead from react-bootstrap-typeahead.
I have a very simple test component :
class AsyncTypeahead2 extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
isLoading: false,
};
}
render() {
return ( <AsyncTypeahead
isLoading={this.state.isLoading}
onSearch={query => {
this.setState({isLoading: true});
fetch("http://www.myHTTPenpoint.com")
.then(resp => resp.json())
.then(json => this.setState({
isLoading: false,
options: json.items,
}));
}}
options={this.state.options}
labelKey={option => `${option.stateName}`}
/> )
}
}
const url = "http://www.myHTTPenpoint.com"
fetchMock
.reset()
.get(
url,
{
items: [
{id:1, stateName:"Alaska"},
{id:2, stateName:"Alabama"}
]
},
);
(Note that the URL is mocked to return two elements)
When I run this in my storybook it looks fine :
But if I want to test it (with Enzyme) it does not recognise the < li > items that pop up.
let Compoment =
<div>Basic AsyncTypeahead Example
<AsyncTypeahead2/>
</div>
const wrapper = mount(Compoment);
let json = wrapper.html();
let sel = wrapper.find(".rbt-input-main").at(0)
sel.simulate('click');
sel.simulate('change', { target: { value: "al" } });
expect(wrapper.find(".rbt-input-main").at(0).getElement().props.value).toBe("al")
expect(wrapper.find(".dropdown-item").length).toBe(2) //but get just 1 element "Type to Search..."
Instead of finding two "dropdown-item" items there is just one item with the text "Type to Search...".
Is the AynchTypeahead not updating the DOM correctly with respect to Enzyme?
<AsyncTypeahead> is asynchronous. On the other hand simulate() is synchronous. So at the time you get to expect() AsyncTypeahead not even started to populate the dropdown with <li> elements. You need to wait for it.
It's not specified, but it looks like you are using fetch-mock package.
There is the flush function which
Returns a Promise that resolves once all fetches handled by fetch-mock have resolved
So this:
...
sel.simulate('click');
sel.simulate('change', { target: { value: "al" } });
await fetchMock.flush() // !!!
expect(wrapper.find(".rbt-input-main").at(0).getElement().props.value).toBe("al")
expect(wrapper.find(".dropdown-item").length).toBe(2)
should work.
...But probably it won't. Because
fetchMock.mock(...)
fetch(...)
await fetchMock.flush()
does work, but
fetchMock.mock(...)
setTimeout(() => fetch(...), 0)
await fetchMock.flush()
does not. await fetchMock.flush() returns right away if there was no call of fetch. And probably there won't be. Because <AsyncTypeahead> debounces.
(By the way, you can also try to mock fetch on a per-test basis. Just in case.)
So I see two options:
Use something else instead of fetch-mock package. Where you can resolve your own Promises on mocked requests completion.
https://tech.travelaudience.com/how-to-test-asynchronous-data-fetching-on-a-react-component-ff2ee7433d71
import waitUntil from 'async-wait-until';
...
test("test name", async () => {
let Compoment = <AsyncTypeahead2/>
...
await waitUntil(() => wrapper.state().isLoading === false);
// or even
// await waitUntil(() => wrapper.find(".dropdown-item").length === 2, timeout);
expect(...)
})
This options if not pretty. But maybe it's your only option - there is not only the fetch-mock you should worry about. setState also asynchronous... and it looks like there is no pretty way to check when it's done updating the state and the DOM without changing the real code (which is quite undesirable).
The exact solution to my problem is in the following code (copy and paste into a JS file to see it work).
Things to note :
I needed to use the waitUntil function from the async-wait-until library. fetch-mock on its own does not provide the functionality to test async code.
I needed to add an ugly hack at global.document.createRange because of some tooltip issue with react-bootstrap-typeahead and jest.
use waitUntil to wait on changes on the internal state of the component
It is very important to call wrapper.update() to update the DOM afterwards.
..
import React, {Component} from 'react';
import waitUntil from 'async-wait-until';
import {mount} from "enzyme";
import fetchMock from "fetch-mock";
import {AsyncTypeahead} from "react-bootstrap-typeahead";
describe('Autocomplete Tests ', () => {
test(' Asynch AutocompleteInput ', async () => {
class AsyncTypeaheadExample extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
isLoading: false,
finished: false
};
}
render() {
return (<AsyncTypeahead
isLoading={this.state.isLoading}
onSearch={query => {
this.setState({isLoading: true});
fetch("http://www.myHTTPenpoint.com")
.then(resp => resp.json())
.then(json => this.setState({
isLoading: false,
options: json.items,
finished: true
}));
}}
options={this.state.options}
labelKey={option => `${option.stateName}`}
/>)
}
}
const url = "http://www.myHTTPenpoint.com"
fetchMock
.reset()
.get(
url,
{
items: [
{id: 1, stateName: "Alaska"},
{id: 2, stateName: "Alabama"}
]
},
);
let Compoment =
<AsyncTypeaheadExample/>
// ugly hacky patch to fix some tooltip bug
// https://github.com/mui-org/material-ui/issues/15726
global.document.createRange = () => ({
setStart: () => {
},
setEnd: () => {
},
commonAncestorContainer: {
nodeName: 'BODY',
ownerDocument: document,
},
});
let wrapper = mount(Compoment);
let sel = wrapper.find(".rbt-input-main").at(0)
sel.simulate('click');
sel.simulate('change', {target: {value: "al"}});
expect(wrapper.find(".rbt-input-main").at(0).getElement().props.value).toBe("al")
//now the async stuff is happening ...
await waitUntil(() => {
return wrapper.state().finished === true;
}, 3000); //wait about 3 seconds
wrapper.update() //need to update the DOM!
expect(wrapper.find(".dropdown-item").length).toBe(2) //but get just 1 element "Type to Search..."
})
});
UPDATE
I can also compare on wrapper items rather than doing a direct comparison on the state :
//now the async stuff is happening ...
await waitUntil(() => {
wrapper.update() //need to update the DOM!
return wrapper.find(".dropdown-item").length > 1
}, 3000); //wait about 3 seconds
This is probably better because it means i dont need to know about the component internals.
I have a function that returns and treats a promise, I need to cover the return that is inside then but I don't know how I can do this, I'm currently trying as follows:
confirmRemoveUser(user: IUser) {
this.modalService
.open('Confirma a exclusão do usuário selecionado?', {
titleText: 'Confirmando exclusão',
confirmButtonText: 'Sim',
cancelButtonText: 'Cancelar',
closeButtonText: 'Fechar',
buttonType: 'danger'
})
.result.then(
(result: BentoModalConfirmationCloseReason) => {
if (result === BentoModalConfirmationCloseReason.Confirm) {
if (this.removeUser(user)) {
this.toastService.open('Usuário excluído com sucesso!', { type: 'success', close: true });
} else {
this.toastService.open('Falha ao excluir o usuário!', { type: 'warning', close: true, duration: 0 });
}
}
}
);
}
I'm currently using callthrough () and imagine that with some parameter I can get the promise but I don't know how:
it('Given_ConfirmRemoveUser_When_UserStepIsCalled_Then_UserIsRemoved', (done) => {
component.selectedJob = {
};
component.selectedArea = {
};
component.users = [{
}];
spyOn(modalService, 'open').withArgs('This is modal msg').and.callThrough();
component.confirmRemoveUser(component.users[0]);
expect(modalService.open).toHaveBeenCalled();
done();
});
And my coverage is like the image below:
Image here!
UPDATE
New Error
Your test should work when it is rewritten as follows:
it('Given_ConfirmRemoveUser_When_UserStepIsCalled_Then_UserIsRemoved', (done) => {
spyOn(modalService, 'open').and.returnValue(Promise.resolve(BentoModalConfirmationCloseReason.Confirm));
spyOn(toastService, 'open').and.stub();
component.confirmRemoveUser(component.users[0])
.then(r => {
expect(toastService.open).toHaveBeenCalled();
done();
})
.catch(e => fail(e));
});
You probably also want to know what will be displayed in the toast. Therefore it makes sense to rather use expect(toastService.open).toHaveBeenCalledWith(?);.
UPDATE
Above solution only works if confirmRemoveUser would return a Promise.
confirmRemoveUser(user: IUser) {
return this.modalService
...
In your case, the use of the done function does not make sense. You need to use async and await.
it('Given_ConfirmRemoveUser_When_UserStepIsCalled_Then_UserIsRemoved', async () => {
spyOn(modalService, 'open').and.returnValue(Promise.resolve(BentoModalConfirmationCloseReason.Confirm));
spyOn(toastService, 'open').and.stub();
await component.confirmRemoveUser(component.users[0]);
expect(toastService.open).toHaveBeenCalled();
});
The same can be achieved with fakeAsync and flush.
import { fakeAsync, flush } from '#angular/core/testing';
...
it('Given_ConfirmRemoveUser_When_UserStepIsCalled_Then_UserIsRemoved', fakeAsync(() => {
spyOn(modalService, 'open').and.returnValue(Promise.resolve(BentoModalConfirmationCloseReason.Confirm));
spyOn(toastService, 'open').and.stub();
component.confirmRemoveUser(component.users[0]);
flush();
expect(toastService.open).toHaveBeenCalled();
}));
I have this weird situation which I don't understand.
In my vue component I use "Repository / Service" for making API calls. It uses axios:
I import it in a component:
import { RepositoryFactory } from "AMComponents/repositories/repository-factory";
const ContactsRepository = RepositoryFactory.get("contacts");
And in method addContact I use it like that:
Now,
This is how I test it:
test("addContact", () => {
const newContact = {
"name": "Hulk Hogan",
"email": "hulk#hogan.com",
"phone": "",
"additional_information": "Hulkamania is running wild, Brother",
"type": "advertiser",
};
ContactsRepository.createContact = jest.fn()
.mockResolvedValue({
data: {
response: {
contact_information: [...contacts, newContact],
passport_privileges: {},
},
},
})
.mockRejectedValue({
response: {
status: 400,
data: {
messages: ["mocked error"],
},
},
});
window.toastr = {
success: jest.fn(),
error: jest.fn(),
};
wrapper.vm.addContact(newContact);
expect(wrapper.vm.saving).toBe(true);
expect(ContactsRepository.createContact).toHaveBeenCalled();
flushPromises()
.then(() => {
expect(1).toBe(2); // <-- here is where I expect my test to fail
expect(wrapper.vm.saving).toBe(false);
expect(window.toastr.error).toHaveBeenCalled();
expect(wrapper.emitted("update")[0][0]).toEqual([...contacts, newContact]);
})
.catch((error) => {
throw Error(error)
})
});
What I exppect my test to fail because I use assertion expect(1).toBe(2).
Instead I have a result like that:
I have spend like 5h trying different solutions to make this work, with no luck.
Can you explain to me what is going on here? Or at least point me to right direction.
After spending another day I am able to suplie solution to my problem.
I have modified jest-setup.js to be able to use async await.
- test("addContact", () => {
+ test("addContact", async () => {
... // no changes
- flushPromises()
- .then(() => {
+ await flushPromises();
expect(1).toBe(2); // <-- now test fail here as expected ;-)
expect(wrapper.vm.saving).toBe(false);
expect(window.toastr.error).toHaveBeenCalled();
expect(wrapper.emitted("update")[0][0]).toEqual([...contacts, newContact]);
})
- .catch((error) => {
- throw Error(error)
- })
});
Anthough this works correctly now, I still don't know why Promise didin't work. So any suggestions are still welcome :)
I have written a pipe that filters an input observable. In the pipe I specify a timeout with the timeout() operator to abort waiting if the expected value is not emitted by the source in time.
I want to test the timeout case with jasmine-marbles, but I can't get it to work.
I believe that expect(source).toBeObservable() evaluates before the source emits.
see Stackblitz
The pipe to be tested:
source = cold('a', { a: { id: 'a' } }).pipe(
timeout(500),
filter((a) => false),
catchError((err) => {
return of({ timeout: true })
}),
take(1)
);
Testing with toPromise() works as expected:
expect(await source.toPromise()).toEqual({ timeout: true });
Testing with jasmine-marbles
const expected = cold('500ms (a|)', { a: { timeout: true } });
expect(source).toBeObservable(expected);
fails with the error
Expected $.length = 0 to equal 2.
Expected $[0] = undefined to equal Object({ frame: 500, notification: Notification({ kind: 'N', value: Object({ timeout: true }), error: undefined, hasValue: true }) }).
Expected $[1] = undefined to equal Object({ frame: 500, notification: Notification({ kind: 'C', value: undefined, error: undefined, hasValue: false }) }).
Support for time progression was recently added (see jasmine-marbles PR #38) to jasmine-marbles 0.5.0. Additional test specs were added to the package that demonstrate one of a couple of possible ways to accomplish what you want. Here are some options I was able to throw together using your Stackblitz sample.
Option 1
When you initialize the source observable outside the test method (e.g. in beforeEach), you must explicitly initialize and pass the test scheduler to timeout to get expect().toBeObservable() working. However, take note that this change will break the "should work with toPromise" test. (I don't know why, but toPromise() doesn't appear to work with this approach.)
describe('Marble testing with timeout', () => {
let source;
beforeEach(() => {
// You must explicitly init the test scheduler in `beforeEach`.
initTestScheduler()
source = cold('a', { a: { id: 'a' } }).pipe(
// You must explicitly pass the test scheduler.
timeout(500, getTestScheduler()),
filter((a) => false),
catchError(err => {
return of({ timeout: true })
}),
take(1)
);
});
it('should work with toBeObservable', () => {
const expected = cold('500ms (a|)', { a: { timeout: true } });
expect(source).toBeObservable(expected);
});
});
Option 2
You can refactor things slightly and initialize the source observable inside the test method (not in beforeEach). You don't need to explicitly initializes the test scheduler (jasmine-marbles will do it for you before the test method runs), but you still have to pass it to timeout. Note how the createSource function can be used with the test scheduler or the default scheduler (if the scheduler argument is left undefined). This options works with both the "should work with toPromise" test and the "should work with toBeObservable" test.
describe('Marble testing with timeout', () => {
const createSource = (scheduler = undefined) => {
return cold('a', { a: { id: 'a' } }).pipe(
// You must explicitly pass the test scheduler (or undefined to use the default scheduler).
timeout(500, scheduler),
filter((a) => false),
catchError(err => {
return of({ timeout: true })
}),
take(1)
);
};
it('should work with toPromise', async () => {
const source = createSource();
expect(await source.toPromise()).toEqual({ timeout: true });
});
it('should work with toBeObservable', () => {
const source = createSource(getTestScheduler());
const expected = cold('500ms (a|)', { a: { timeout: true } });
expect(source).toBeObservable(expected);
});
});
Option 3
Finally, you can skip passing the test scheduler to timeout if you explicitly use the test scheduler's run method, but you must use expectObservable (as opposed to expect().toBeObservable(). It works just fine, but Jasmine will report the warning "SPEC HAS NO EXPECTATIONS".
describe('Marble testing with timeout', () => {
let source;
beforeEach(() => {
source = cold('a', { a: { id: 'a' } }).pipe(
timeout(500),
filter((a) => false),
catchError(err => {
return of({ timeout: true })
}),
take(1)
);
});
it('should work with scheduler and expectObservable', () => {
const scheduler = getTestScheduler();
scheduler.run(({ expectObservable }) => {
expectObservable(source).toBe('500ms (0|)', [{ timeout: true }]);
});
});
});
I am getting a timeout of 2000ms exceeded message when running the following tests for my Backbone application.
How can I get this test to pass?
I am also trying to listen for the event's being triggered when calling more. How could this be tested?
describe("Foo.Collection.Items/Discover", function () {
describe("More method", function () {
beforeEach(function () {
this.server = sinon.fakeServer.create();
this.hasLength = sinon.spy(Foo.View.ItemFeed.prototype, "toggleFeedback");
this.noLength = sinon.spy(Foo.View.ItemFeed.prototype, "stopLazyload");
this.item1 = new Foo.Model.item({
description: "A swell minions movie!",
for_sale: false,
title: "Minions: Goldfinger",
link: "/discover",
'private': false,
'main_image': false
});
this.item2 = new Foo.Model.item({
description: "A round pot",
for_sale: true,
title: "Pot",
link: "/discover",
'private': true,
'main_image': true
});
this.itemsDiscover = new Foo.Collection.Items([this.item1, this.item2], {url: "/discover"});
});
afterEach(function () {
this.server.restore();
this.hasLength.restore();
this.noLength.restore();
});
it("should fetch items and trigger moreFetched", function (done) {
this.server.respondWith('GET', "/discover", [
200,
{"Content-type": "application/json"},
JSON.stringify([this.item1, this.item2])
]);
this.itemsDiscover.once("add", function () {
expect(this.itemsDiscover).to.have.length(2);
expect(this.hasLength).to.be.calledOnce();
done();
});
this.itemsDiscover.more();
});
});
});
The part of the Backbone Collection I am trying to test:
more: function () {
var collection = this;
this.fetch({
success: function (collection, response) {
if (response.length) {
collection.trigger('moreFetched');
} else {
collection.trigger('emptyFetched');
}
},
reset: false,
remove: false
});
}
I guess that you have an exception that avoids to call done, try
this.itemsDiscover.once("add", function () {
try {
expect(this.itemsDiscover).to.have.length(2);
expect(this.hasLength).to.be.calledOnce();
done();
} catch(e) {
done(e);
}
});
If you get an error then post it, because I think what it is.
I think I see what's going on: your test method is dependent on the add event being triggered in order to get into the callback that verifies the data. However, the way you've set up this.itemsDiscover, it contains this.item1 and this.item2 already:
....
this.itemsDiscover = new Foo.Collection.Items([this.item1, this.item2], {url: "/discover"});
Then, your mocking out of the URL will also return the string version of an array containing this.item1 and this.item2:
...
this.server.respondWith('GET', "/discover", [
200,
{"Content-type": "application/json"},
JSON.stringify([this.item1, this.item2])
]);
...
Here's the kicker: the add event will never be fired by the collection, because the two items returned already exist in the collection. D'oh.
I suggest changing the test to wait for a sync event instead, which is always fired after a successful fetch:
this.itemsDiscover.once("sync", function () {
expect(this.itemsDiscover).to.have.length(2);
expect(this.hasLength).to.be.calledOnce();
done();
});
I expect that will get your test code running.