I want to generate two separate report for a single test case. For that, I am using browser.getCapabitities method in the test by which I am getting the browser name and version.
Now, when I use this variable at the end of the spec description, the value is undefined. The browserNameforSpec is getting value before describe. Only when I use this value at the end of the spec, it shows undefined. I am not able to get the reason why this happens. Is there any way to change the name of this spec description before test started.
My code is
let capsPromise = browser.getCapabilities();
let browserNameforSpec;
capsPromise.then(function(caps) {
console.log(caps);
let browserName = caps.get('browserName');
let browserVersion = caps.get('version');
browserNameforSpec = browserName + '-' + browserVersion + '-';
console.log(browserNameforSpec);
});
describe( '0030 Test for login' + browserNameforSpec, function () { // this.browserNameforSpec value is undefined
// 1.
it('Navigate to the login page', async () => {
await navigate.to.the(loginPage);
});
// 2
it('Click onto language button', async() => {
await click.onto(languageButton);
await expect(languageDropdown.isDisplayed());
});
// 3
it('English Language is selected', async() => {
await click.onto(englishLanguage);
await expect(languageButton.getText()).toBe('English');
});
// 4.
it('Correct user name is written into email field', async() => {
await usernameField.click();
await enter(correctUsername, into(usernameField));
});
// 5.
it('Correct password is written into password field', async() => {
await passwordField.click().then(function () {
passwordField.clear();
enter(correctPassword, into(passwordField));
})
});
// 6.
it('Login button is clicked and home page is opened', async() => {
await click.onto(loginButton);
});
});
Add the below code in your onPrepare()
browser.getCapabilities().then(function (cap) {
browser.browserName = cap.caps_.browserName;
});
You call in your test as below
describe( '0030 Test for login' + browser.browserName, function () {
// 1.
it('Navigate to the login page', async () => {
await navigate.to.the(loginPage);
});
Hope it helps you..
Issue is :
1. You are using this.browserNameforSpec which will be undefined as the function context gets changed, You have declared browserNameforSpec as a variable which is directly available in all function but you are calling on this)
2. browser.getCapabilities() returning an instance of Promise that's why the execution flow is different. First it is executing this function and the describe(). But. they need to be called in sync manner.
Below code is using another .then for executing it in a sequential manner. Try to use below code :
let capsPromise = browser.getCapabilities();
let browserNameforSpec;
capsPromise
.then(function(caps) {
console.log(caps);
let browserName = caps.get('browserName');
let browserVersion = caps.get('version');
browserNameforSpec = browserName + '-' + browserVersion + '-';
console.log(browserNameforSpec);
})
.then(function() {
describe( '0030 Test for login' + browserNameforSpec, function () {
// 1.
it('Navigate to the login page', async () => {
await navigate.to.the(loginPage);
});
// 2
it('Click onto language button', async() => {
await click.onto(languageButton);
await expect(languageDropdown.isDisplayed());
});
// 3
it('English Language is selected', async() => {
await click.onto(englishLanguage);
await expect(languageButton.getText()).toBe('English');
});
// 4.
it('Correct user name is written into email field', async() => {
await usernameField.click();
await enter(correctUsername, into(usernameField));
});
// 5.
it('Correct password is written into password field', async() => {
await passwordField.click().then(function () {
passwordField.clear();
enter(correctPassword, into(passwordField));
})
});
// 6.
it('Login button is clicked and home page is opened', async() => {
await click.onto(loginButton);
});
});
});
Related
So i'm trying to testing on my button that run the function asynchronously. this is my button logic looks like.
// Function below will run when user click the button
this._pageModule.favoriteButtonCallback = async () => {
try {
// I want to expect run after this await below is done
await this._favoriteRestaurants.PutRestaurant(this._restaurant);
console.log(
'console log in button',
await this._favoriteRestaurants.GetAllRestaurant(),
);
this._renderButton();
return Promise.resolve(
`Success add ${this._restaurant.name} to favorite!`,
);
} catch (err) {
this._renderButton();
return Promise.reject(
new Error(
`Failed add ${this._restaurant.name} to favorite! Error: ${err}`,
).message,
);
}
};
and this is my test
fit('should be able to add the restaurant to favorite', async () => {
expect((await RestaurantIdb.GetAllRestaurant()).length).toEqual(0);
// spyOn(RestaurantIdb, 'PutRestaurant');
document.body.innerHTML = `<detail-module></detail-module>
<modal-element></modal-element>`;
const pageModule = document.querySelector('detail-module');
await FavoriteButtonInitiator.init({
pageModule,
restaurant,
favoriteRestaurants: RestaurantIdb,
});
pageModule.restaurantDetail = restaurant;
await pageModule.updateComplete;
const favoriteButton = pageModule.shadowRoot
.querySelector('[aria-label="favorite this restaurant"]')
.shadowRoot.querySelector('button');
// 1. Simulate user click the button
favoriteButton.dispatchEvent(new Event('click'));
// expect(RestaurantIdb.PutRestaurant).toHaveBeenCalled();
const restaurants = await RestaurantIdb.GetAllRestaurant();
console.log('console log from test', restaurants);
expect(restaurants).toEqual([restaurant]);
});
i'm using lit-element, simply it similar with react, i have custom element <define-module> with button inside. then i give the required properties to it, then it will render.
This is my test log Test log
as you can see the console log from the test ran before the console log that i put in the button. and it is empty array.
what i want is when click event dispatched. the next line in the test wait until the asynchronous function in the button done, how do i make it possible?
What have i done:
i have tried to console log them.
i have tried to using done in jasmine, but it doesn't work since i using async/await in the test.
I have tried use spyOn, but i don't really understand how to spy indexedDb
UPDATE
So i have found what caused problem, here i have simplified my code.
/* eslint-disable */
import { openDB } from 'idb';
import { CONFIG } from '../src/scripts/globals';
const { DATABASE_NAME, DATABASE_VERSION, OBJECT_STORE_NAME } = CONFIG;
const dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {
upgrade(database) {
database.createObjectStore(OBJECT_STORE_NAME, { keyPath: 'id' });
},
});
const RestaurantIdb = {
async GetRestaurant(id) {
return (await dbPromise).get(OBJECT_STORE_NAME, id);
},
async GetAllRestaurant() {
return (await dbPromise).getAll(OBJECT_STORE_NAME);
},
async PutRestaurant(restaurant) {
if (await this.GetRestaurant(restaurant.id)) {
return Promise.reject(
new Error('This restauant is already in your favorite!').message,
);
}
return (await dbPromise).put(OBJECT_STORE_NAME, restaurant);
},
async DeleteRestaurant(id) {
if (await this.GetRestaurant(id)) {
return (await dbPromise).delete(OBJECT_STORE_NAME, id);
}
return Promise.reject(
new Error('This restauant is not in favorite!').message,
);
},
};
describe('Testing RestaurantIdb', () => {
const removeAllRestaurant = async () => {
const restaurants = await RestaurantIdb.GetAllRestaurant();
for (const { id } of restaurants) {
await RestaurantIdb.DeleteRestaurant(id);
}
};
beforeEach(async () => {
await removeAllRestaurant();
});
afterEach(async () => {
await removeAllRestaurant();
});
it('should add restaurant', async () => {
document.body.innerHTML = `<button></button>`;
const button = document.querySelector('button');
button.addEventListener('click', async () => {
await RestaurantIdb.PutRestaurant({ id: 1 });
});
button.dispatchEvent(new Event('click'));
setTimeout(async () => {
const restaurants = await RestaurantIdb.GetAllRestaurant();
console.log('console log in test', restaurants);
expect(restaurants).toEqual([{ id: 1 }]);
}, 0);
});
});
And this is the result Test Result
I assume that IndexedDb takes times to put my restaurant data. and i still can't figure out how to fix it.
If you were using Angular, you would have access to fixture.whenStable(), and fakeAsync and tick() which wait until promises are resolved before carrying forward with the test.
In this scenario, I would try wrapping what you have in the test in a setTimeout
fit('should be able to add the restaurant to favorite', async () => {
expect((await RestaurantIdb.GetAllRestaurant()).length).toEqual(0);
// spyOn(RestaurantIdb, 'PutRestaurant');
document.body.innerHTML = `<detail-module></detail-module>
<modal-element></modal-element>`;
const pageModule = document.querySelector('detail-module');
await FavoriteButtonInitiator.init({
pageModule,
restaurant,
favoriteRestaurants: RestaurantIdb,
});
pageModule.restaurantDetail = restaurant;
await pageModule.updateComplete;
const favoriteButton = pageModule.shadowRoot
.querySelector('[aria-label="favorite this restaurant"]')
.shadowRoot.querySelector('button');
// 1. Simulate user click the button
favoriteButton.dispatchEvent(new Event('click'));
// expect(RestaurantIdb.PutRestaurant).toHaveBeenCalled();
setTimeout(() => {
const restaurants = await RestaurantIdb.GetAllRestaurant();
console.log('console log from test', restaurants);
expect(restaurants).toEqual([restaurant]);
}, 0);
});
The things in the setTimeout should hopefully happen after the asynchronous task of the button click since promises are microtasks and setTimeout is a macrotask and microtasks have higher priority than macrotasks.
I need to test an async Node.js library which periodically generates events (through EventEmitter) until done. Specifically I need to test data object passed to these events.
The following is an example using mocha + chai:
require('mocha');
const { expect } = require('chai');
const { AsyncLib } = require('async-lib');
describe('Test suite', () => {
const onDataHandler = (data) => {
expect(data.foo).to.exist;
expect(data.bar).to.exist;
expect(data.bar.length).to.be.greaterThan(0);
};
it('test 1', async () => {
const asyncLib = new AsyncLib();
asyncLib.on('event', onDataHandler); // This handler should be called/tested multiple times
await asyncLib.start(); // Will generate several 'events' until done
await asyncLib.close();
});
});
The problem is that even in case of an AssertionError, mocha marks the test as passed and the program terminates with exit code 0 (instead of 1 as I expected).
The following uses done callback instead of async syntax, but the result is the same:
require('mocha');
const { expect } = require('chai');
const { AsyncLib } = require('async-lib');
describe('Test suite', () => {
const onDataHandler = (data) => {
expect(data.foo).to.exist;
expect(data.bar).to.exist;
expect(data.bar.length).to.be.greaterThan(0);
};
it('test 1', (done) => {
const asyncLib = new AsyncLib();
asyncLib.on('event', onDataHandler);
asyncLib.start()
.then(asyncLib.close)
.then(() => done());
});
});
I have also tried with a "pure" Node.js approach using the native assert.ok without any 3rd part library:
const { strict: assert } = require('assert');
const { AsyncLib } = require('async-lib');
const test = async () => {
const onDataHandler = (data) => {
assert.ok(data.foo != null);
assert.ok(data.bar != null);
assert.ok(data.bar.length > 0);
};
asyncLib.on('event', onDataHandler);
const asyncLib = new AsyncLib();
await asyncLib.start();
await asyncLib.close();
}
(async () => {
await test();
})();
Even in this case, an AssertionError would make the program to terminate with exit code 0 instead of 1.
How can I properly test this code and make the tests correctly fail in case of an assertion error?
There are some things that you need to fix to make it works:
Make your test async, because the test is going to execute the expects after a certain event is received meaning it's going to be asyncronous.
Your event handler in this case onDataHandler should receive the done callback because there is the way how you can indicate to mocha that the test was finished successful as long as the expects don't fail.
I wrote some code and tested it out and it works, you have to make some changes to adapt your async library though:
describe('Test suite', function () {
const onDataHandler = (data, done) => {
expect(data.foo).to.exist;
expect(data.bar).to.exist;
expect(data.bar.length).to.be.greaterThan(0);
done();
};
it('test 1', async function (done) {
eventEmitter.on('event', (data) => onDataHandler(data, done));
setTimeout(() =>{
eventEmitter.emit('event', {
})
}, 400)
});
});
I was trying to use .then() with my test cases but without success because of strage comportament. I'm trying make tests with google chrome to.
i have the "SELENIUM_PROMISE_MANAGER: false," in my conf.js file.
Now the problem:
When i trying to find some elements in the DOM i has problems...the actual error is:
Failed: Failed: element not interactable
The CODE (With comments)
console.log('Testing Pesquisa Assunto ...');
beforeAll(async function () {
var teste = await browser.get(browser.params.URL_PROCESSO).then(function () {
})
});
it('Deve escolher um ASSUNTO PRINCIPAL e verificar os resultados', async function () {
try {
if ( await browser.findElements(by.id('filtro_assuntos')).toEqual(""));
} catch{
let btnMaisFiltros = element(by.id('maisFiltros'))
let placeAssunto = element(by.css('[placeholder = "Assunto"]'))
let listAssuntos = element.all(by.className('mat-option-text')).get(2)
let habilitaAssuntoP = element(by.className('mat-slide-toggle-bar'))
let aplicar = element(by.className("aplicar"))
await btnMaisFiltros.click()
console.log('Entered here 1')
await placeAssunto.click()
console.log('Entered here 2') //CANNOT ENTER HERE
await listAssuntos.click();
console.log('Entered here 3')
await habilitaAssuntoP.click()
console.log('Entered here 4')
await aplicar.click()
console.log('Entered here 5')
}
})```
I'm trying to test a function with a callback inside. I set up a mock function, but I also need to test a callback.
I've tried to separate it as another mock function, but it doesn't counted as covered.
Function I'm trying to test:
export const checkDescription = async page => {
const metaDescription = await page.$eval(
'meta[name="description"]',
description => description.getAttribute("content")
);
return metaDescription;
};
I've mocked the page function :
const page = {
$eval: jest.fn(() => "Value")
};
my test :
test("Should return description", async () => {
expect(await checkDescription(page)).toBe("Value");
expect(page.$eval).toHaveBeenCalled();
});
I've tried to separate description :
const description = {
getAttribute: jest.fn(() => "Value")
};
but I don't think that it's a correct way to cover description inside $eval.
You're close!
The description arrow function is passed to your page.$eval mock function so you can use mockFn.mock.calls to retrieve it.
Once you've retrieved it, you can call it directly to test it and get full code coverage:
test("Should return description", async () => {
expect(await checkDescription(page)).toBe("Value"); // Success!
expect(page.$eval).toHaveBeenCalled(); // Success!
const description = page.$eval.mock.calls[0][1]; // <= get the description arrow function
const getAttributeMock = jest.fn(() => 'mock content');
expect(description({ getAttribute: getAttributeMock })).toBe('mock content'); // Success!
expect(getAttributeMock).toHaveBeenCalledWith('content'); // Success!
// Success! checkDescription now has full code coverage
});
I receive async messages from serial port via callbacks. Try to read here:
https://jest-bot.github.io/jest/docs/asynchronous.html
import { InpassTerminal } from "../src/main.js"
jest.setTimeout(45000);
describe('Basic tests', () => {
test('1. Host connection', async (done) => {
await new Promise( resolve => setTimeout(resolve, 500) );
const commandTest = {actionCode: '12345', terminalId: '1019****'}
function cb (data) {
if (data.operationCode == 12345) {
const actualStatus = Buffer.from(data.status, "ascii")
const expectedStatus = '1'
expect(actualStatus.toString()).toBe(expectedStatus)
done()
}
}
const terminal = new InpasTerminal()
terminal.exec('/dev/ttyPos0', commandTest, cb)
})
I wonder why my second console.log() not logs anything to the console...
describe('Puppeteer', () => {
it('Does not log', () => {
(async () => {
console.log('This logs'); // <- works
const browser = await puppeteer.launch({
headless: true,
args: [
'--incognito'
]
});
await console.log('This does not log'); // <- Does not work
console.log('This does not log too'); // <- This neither
const page = await browser.newPage();
await page.goto('....');
....
expect(a < b)
.toEqual(true);
browser.close();
})();
});
});
Is there any reason why that does not log?
Solution: This does not work because you are running the block instantly. Make sure to pass a function which is not self executing.
A example of self executing function is (()=>{})(). This prevents the test from resolving properly.
Here is the cleaned up code:
const puppeteer = require('puppeteer');
const assert = require('assert');
describe('Puppeteer', () => {
it('Does log', async () => { // <== PASS THE FUNCTION HERE
const browser = await puppeteer.launch({args: ['--incognito']});
console.log('This logs now');
const page = await browser.newPage();
await page.goto('https://example.org');
const title = await page.title();
assert.equal(title, 'Example Domain');
console.log('This logs too');
await browser.close();
})
});
Result:
The question has jest instead of mocha. Here is the code for jest and result. Which is almost same except following line,
// assert.equal(title, 'Example Domain');
expect(title).toEqual('Example Domain');
Result:
Optionally if you want to stack the logs together, you can pass --verbose=false when running jest.