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')
}
})```
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 am trying to throw an error on the console if the first link of bing search results is clicked. My code is working fine until the first link is opened, but I am not seeing any message on the console that first link is successfully clicked and when I make an intentional code change to catch error, catch is not throwing error. I am using node.js, selenium and edge webdriver. Please help me fix this.
const { Builder, By } = require('selenium-webdriver');
async function launchEdgeBing() {
let driver = await new Builder().forBrowser('MicrosoftEdge').build();
await driver.get('https://bing.com');
await driver.manage().window().maximize();
const element = await driver.findElement(By.id('sb_form_q'));
await driver.sleep(5000);
await element.sendKeys('latest news');
await element.submit();
await driver.sleep(5000);
try {
const clickFirstResult = await driver.findElement(
By.className('b_title')
);
clickFirstResult.click();
await driver.sleep(5000);
var title = await driver.getTitle();
console.log('Title is:', title);
} catch (e) {
if (e == null) {
console.log('First link opened successfully');
} else {
console.log('Error is:', e);
}
} finally {
await driver.quit();
}
}
launchEdgeBing();
So I have this asynchronous function with inquirer and fs.writeFile inside
(async () => {
...
if (process.env.IG_USERNAME && process.env.IG_PASSWORD) {
console.log(`Used as ${chalk.green(process.env.IG_USERNAME)}`);
} else {
console.log(`\nInstagram account data is not yet put in \nInputting in...`);
await inquirer.prompt(questions).then((answers) => {
let file = `IG_USERNAME=${answers.username}\nIG_PASSWORD=${answers.password}\n#ONLINE_MODE=true`;
fs.writeFile(".env", file, (err) => {
if (err) console.log("Something went wrong..");
else console.log(`Used as ${chalk.green(process.env.IG_USERNAME)}`);
});
});
}
await login();
...
})();
the login(); function needs the .env variable, i input it using inquirer but the login(); function get executed before the inquirer answer get processed.
What should I do to make the login(); waits until the fs.writeFile is finished?
The short answer is to ONLY use promise-based asynchronous operations inside your .then() so you can properly chain all promises and then the higher level await will wait for everything. In this case, you can use return fs.promises.writeFile(...) (instead of fs.writeFile(...)) because fs.promises.writefile(...) returns a promise and will then properly chain with the parent promise.
(async () => {
...
if (process.env.IG_USERNAME && process.env.IG_PASSWORD) {
console.log(`Used as ${chalk.green(process.env.IG_USERNAME)}`);
} else {
console.log(`\nInstagram account data is not yet put in \nInputting in...`);
await inquirer.prompt(questions).then((answers) => {
let file = `IG_USERNAME=${answers.username}\nIG_PASSWORD=${answers.password}\n#ONLINE_MODE=true`;
return fs.promises.writeFile(".env", file);
});
}
await login();
...
})();
Or, simplified a little more:
(async () => {
...
if (process.env.IG_USERNAME && process.env.IG_PASSWORD) {
console.log(`Used as ${chalk.green(process.env.IG_USERNAME)}`);
} else {
console.log(`\nInstagram account data is not yet put in \nInputting in...`);
const answers = await inquirer.prompt(questions);
const file = `IG_USERNAME=${answers.username}\nIG_PASSWORD=${answers.password}\n#ONLINE_MODE=true`;
await fs.promises.writeFile(".env", file);
}
await login();
...
})();
Generally either use .then() or await with promises, not both together. And login() is getting executed before because the promise is getting resolved via .then().
And there is no promise returned to await for before calling login().
Solution 1: The quick fix is to resolve await login(); inside the callback of fs.writeFile, but then login()'s error would have to be handled as well, which just makes the code more verbose to begin with.
const answers = await inquirer.prompt(questions);
let file = `IG_USERNAME=${answers.username}\nIG_PASSWORD=${answers.password}\n#ONLINE_MODE=true`;
fs.writeFile(".env", file, async (err) => {
if (err) console.error("Error:fs.writeFile()::", err);
else console.log(`Used as ${chalk.green(process.env.IG_USERNAME)}`);
try {
await login();
} catch (e) {
console.error("Error::login():", e);
}
});
Solution 2: util.promisify with Node >= V8
Make the fs.writeFile to a promise.
const fs = require("fs");
const { promisify } = require("util");
const promisedWriteFile = promisify(fs.writeFile);
try {
const answers = await inquirer.prompt(questions);
let file = `IG_USERNAME=${answers.username}\nIG_PASSWORD=${answers.password}\n#ONLINE_MODE=true`;
await promisedWriteFile(".env", file);
await login();
} catch (error) {
console.error("Any error::", error);
}
Solution 3: fs Promises API with Node >= V10
try {
const answers = await inquirer.prompt(questions);
let file = `IG_USERNAME=${answers.username}\nIG_PASSWORD=${answers.password}\n#ONLINE_MODE=true`;
await fs.promises.writeFile(".env", file);
await login();
} catch (error) {
console.error("Any error::", error);
}
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.
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);
});
});
});