testcafe - how to assert text contains in html body - javascript

I am using testcafe for api testing however our api requires login. Below is my code. I can see json response fine. But i am not sure how to assert on the page.
import { Selector } from 'testcafe';
import Page from './page';
// Page model
const page = new Page();
const url = 'https://myexample.com';
const elementWithIdOrClassName = Selector(value => {
return document.getElementById(value) || document.getElementsByTagName(value);
});
fixture `Test`
.page(url + '/talent/career')
.beforeEach( async t => {
await t
.typeText(page.username, 'gvp50')
.typeText(page.password, 'password')
.click(page.login_button)
});
// Tests
test('Text typing basics', async t => {
await t
.navigateTo(url+'/api/learner/learning_items')
.expect(Selector('html')).contains('learning_items');
});
Testcafe just hangs after i run this code. I tried Selector('body') as well but it doesn't work.

You need to specify what element property (state) you'd like to obtain (verify).
After you selected the entire 'html' element (Selector('html')), specify what property (state) you'd like to access (attributes, childNodes, style, size, etc.). See the DOM Node State topic to learn more.
It looks like you wanted to access the text content as follows:
.expect(Selector('html').textContent).contains('learning_items');
However, such selector usage is unlikely to be the cause of the hang as TestCafe will properly display a message about invalid selector usage. You might want to simplify your test and/or debug it to find what causes the hang.

const cellcomparedata =await Selector('[role="gridcell"]').textContent;
console.log("cellcomparedata is",cellcomparedata);
either you can use this.

Related

Store web element's value in a parameter and use it in various js files in testcafe

In our insurance domain, the below scenario we want to achieve using testcafe:-
1st file:- Login into the application
2nd file:- create a claim, store the claim number into the global variable
3rd file:- use that globally declared claim number in all the Testscripts.
we are using the Page object model to achieve our scenario.
Please let us know how can we achieve this in testcafe.
As we suspect, the web element value that we get in 2nd file gets vanished as soon as the test case gets executed. so how can we pass that web element value in our 3rd file?
If possible, please let us know the steps in detail.
we have tried the below keywords to define our selector but it didn't work.
global
globalthis
We want to pass the data(fetched web element value) from one testscript to another testscript. Our question is whether it's possible or not
//page.js
import { Selector, t } from 'testcafe';
class PageModel {
constructor() {
global.ClaimNumber = Selector('#Txt_claimnumber');
//selector for Claim Number
this.DateOfEvent = Selector('#dateofevent');
//selector for Date of Event
this.DateOfClaim = Selector('#dateofclaim')
//selector for Date of Claim
this.TimeOfEvent = Selector('#timeofevent')
//selector for Time of Event
this.TimeOfClaim = Selector('#timeofclaim')
//selector for Time of Claim
this.ClaimStatus = Selector('#claimstatus')
//selector for Claim Status
this.Save = Selector('#Save');
//selector for Save Button
}};
export default new PageModel();
//test.js
import { Selector } from 'testcafe';
import PageModel from './page';
fixtureGetting Started
.pagehttps://devexpress.github.io/testcafe/example;
var claimid;//claimid will be generate after saving a claim
test('My first test', async t => {
await t
.typeText(this.DateOfEvent, '20/09/2022')
.typeText(this.DateOfClaim, '20/09/2022')
.typeText(this.TimeOfEvent, '12:00')
.typeText(this.TimeOfClaim, '12:00')
.typeText(this.ClaimStatus, 'xyz')
.click(this.Save)
claimid=global.ClaimNumber.value
//After saving the claim we want to fetch claimid and want to use that claim id in another testscript
});
//test1.js
import { Selector } from 'testcafe';
import PageModel from './page';
import Test from './test'
fixtureGetting Started
.pagehttps://devexpress.github.io/testcafe/example;
test('My first test', async t => {
var claimid1='23445';
await t.expect(claimid1).eql('claimid');
//want to verify claimid getting from test.js is equal to claimid from test1.js or not
//this is just an example but our requirement is to use claimid (getting from test.js) for different different operation into test1.js testscript.
});
Could you please tell us how to achieve this scenario.
It isn't correct to use information from one test in another one. If you want to prepare something before any test starts, you can use hooks. Also, if you need to reuse auth information, use Roles. It will be great practice.
Please see the following example with a global variable:
//test.js
import { Selector } from 'testcafe';
import PageModel from './page';
fixture`Getting Started`
.page`https://devexpress.github.io/testcafe/example`;
test('My first test', async t => {
await t
.typeText(global.developerNameSelector, 'John Smith')
.click('#submit-button')
// Use the assertion to check if the actual header text is equal to the expected one
.expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');
});
//page.js
import { Selector, t } from 'testcafe';
class PageModel {
constructor() {
global.developerNameSelector = Selector('#developer-name');
}
};
export default new PageModel();
As my colleague mentioned above, it is very bad practice to use data from one test in another one. However, if it is required, you can use the "global" object in a common JavaScript way to accomplish this task:
test('My first test', async () => {
global.someVar = 'developer-name';
});
test('My second test', async t => {
await t.typeText(`#${global.someVar}`, 'some text');
});
Note that if, for some reason, the order in which the tests are executed changes (for example, in concurrency mode), then you will encounter unexpected behavior.
Also, I just checked your code and found out that you are trying to save the result of the "expect" method call (Assertion object) to your variable. Would you please clarify why? What behavior are you are trying to achieve?

Check if object contains a link in React Testing Library

Having the following unit test:
const MY_URL = 'example.com'
it('should render MyComponent with url', () => {
const { getByTestId } = render(<MyComponent />);
const myLink = getByTestId(TestIds.LINK);
expect(loggingLink).toContain(MY_URL);
});
The test fails with the following message:
Expected value: "example.com"
Received object: <div class="m-3" data-testid="test-link">my-link</div>
So it seems that toContain doesn't check what is inside of that object. Is there a method to check that the URL is inside the object?
You can get the anchor element with ByRole query. Just search it with link and then check the attribute href:
// I used screen in this case, but you can get getByRole from render.
const anchorElement = screen.getByRole('link');
expect(anchorElement).toBeInTheDocument();
expect(anchorElement).toHaveAttribute('href', 'example.com');
Anchor elements have link role only when href attribute is present, otherwise no corresponding role. You can check more about it here.
There's a couple of things. First, toContain is for testing if an element exists in an array. https://jestjs.io/docs/expect#tocontainitem
Second, the point of RTL is not to test properties and such, but to test what users see on the screen. So I guess the "RTL way" of doing this would be to click the link and see what's displayed. Which admittedly is not always helpful in every situation!
If you are absolutely sure this url needs a test around it, then you do have an escape hatch via the underlying jest jsdom selectors. You can query an element using a bog standard querySelector and then test the href property directly.
In fact you don't even need querySelector. The getBy methods all return a jsdom object which you can then test with getAttribute('href')

Gatsby source plugin only showing last item in array in GraphQL

When I console log after I run build 6 objects show up in my drinks array. They also show up when I run develop. But when I query graphQL only the last object in my array is available. I am new to gatsby and graphQL so included image just in case my query was off.
Code is from my gatsby-node.js file:
exports.sourceNodes = async (
{ actions, createContentDigest, createNodeId,}
) => {
const NODE_TYPE = "CocktailRecipes";
try{
const response = await fetch(`https://www.thecocktaildb.com/api/json/v1/1/search.php?s=vodka`)
const data = await response.json();
const {drinks} = data;
console.log(drinks)
drinks.forEach((drink) => {
actions.createNode({
...drink,
id: createNodeId(`${NODE_TYPE }-${drink.id}`),
parent:null,
children:[],
internal:{
type:NODE_TYPE,
content:JSON.stringify(drink),
contentDigest: createContentDigest(drink)
}
})
})
}
catch(error){
console.log("ERROR")
console.log(error)
}
}
only one object showing in graphQL
If anyone could help it would be very much appreciated as I've been banging my head on a wall for awhile now. I've done a gatsby clean. I've tried map instead of forEach
I've faced exactly the same issue as you a few months ago and, in my case was that I needed to set a valid internal id for each element to allow GraphQL to create a proper schema for each node if not, the id is overridden in each element and it only takes the last one.
In your case, it seems that some field is wrong, making the following expression invalid:
id: createNodeId(`${NODE_TYPE }-${drink.id}`),
Try debugging more what's receiving and changing it to some hardcoded value. Something like:
id: drink.id,
Keep in mind that, if the ids are different for each node, you don't need to use createNodeId API for debugging purposes (but it's recommended).

How to add custom request header to testcafe test suite?

I have a bunch of tests that I am running through testcafe. Now I need to add a custom request header for each test that uniquely identifies the call is originating from the testcafe suite and not a real user.
Is there a way to add the custom header to all the test cases at once?
I was looking at this but it seems like I would need to update each fixture to get this working. So, I wanted to know if there's a way I can set it on a top level file before calling the test suite?
EDIT:
So, this is what I am currently doing. I have created a new file that contains the class:
import { RequestHook } from 'testcafe';
class CustomHeader extends RequestHook {
constructor () {
// No URL filtering applied to this hook
// so it will be used for all requests.
super();
}
onRequest (e) {
e.requestOptions.headers['my_custom_variable'] = 'my_value';
}
onResponse (e) {
// This method must also be overridden,
// but you can leave it blank.
}
}
const customHeader = new CustomHeader();
export default customHeader;
And then in my each test file, update the fixtures to be like this:
import { customHeader } from 'customer_header'
fixture(`Test app avail`)
.page(appURL)
.requestHooks(customHeader)
.beforeEach(async() => {
await myTestfunction();
});
Does this make sense?
Currently there is no way to specify hooks on the test run level. But, if updating each fixture is not reasonable in your case, you can use the workaround posted in the discussion about this feature. In order to apply your request hook to each fixture in the test suite you'll need to change "setup.js" (from the workaround above) as follows:
export const fixture = (...args) => global.fixture(...args)
.requestHooks(customHeader)
.beforeEach(async t => {
console.log('each');
});

TestCafé data driven tests with login

I had written some tests using for loops and recently discovered this handy doc page that describes how to write data-driven tests.
https://devexpress.github.io/testcafe/documentation/recipes/create-data-driven-tests.html
I'm now trying to refactor my tests but running into a problem. The purpose of the test is to log in as a bunch of different accounts, and then verify whether certain page elements exist. (I recognize that this is a heavy hammer to use, but our app has a huge number of permissions and the combinations often get forgotten when developing new features, so this seemed like the quickest way to get at the actual truth of what is on the screen for a real user).
My old tests look something like this:
test('Account manager', async (t) => {
const existingItems = [
[mediaSidePanel.customize, 'Customize'],
[mediaSidePanel.stats, 'Stats'],
[mediaSidePanel.download, 'Download'],
[mediaSidePanel.delete, 'Delete'],
];
const notExistingItems = [
[mediaSidePanel.adminTools, 'Admin Tools'],
];
await t
.useRole(advAccountManager)
.navigateTo(`https://${accountKey}.wistia.io/medias/${mediaHashedID}`);
await Promise.all(existingItems.map(async item => await t
.expect(item[0].exists).ok(`${item[1]} should exist for an Account Manager`)));
await Promise.all(notExistingItems.map(async item => await t
.expect(item[0].exists).notOk(`${item[1]} should not exist for an Account Manager`)));
});
The test works fine except for the obvious problems of having loops in tests: I need to have thorough diagnostic messages to ensure I know which element actually is failing, and worse, if something early in the loop fails, the test ends, and I have no way of knowing if there would have been subsequent failures.
I started trying to refactor this by pulling all of the existing/non-existing items into an array defined in a separate file and wrote this:
import * as dataSet from '../helpers/rolePermissions';
fixture `Advanced Account Manager`
.page `https://app.wistia.io/logout`
.beforeEach(async (t) => {
await t
.useRole(advAccountManager);
});
dataSet.advAccountManager.project.forEach(data => {
test.page `https://${accountKey}.wistia.io/projects/${projectHashedID}`(`Project - ${data.name}`, async t => {
if (data.present) {
await t
.expect(await data.selector.exists).ok(`${data.name} should exist for an Account Manager`);
}
else {
await t
.expect(await data.selector.exists).notOk(`${data.name} should not exist for an Account Manager`);
}
});
});
It works perfectly in that it gets rid of the biggest problem and keeps running the tests even if an earlier one fails. It introduces a much bigger problem, however. This is now considerably slower because it has to log in every single time it iterates through the test. I am already using Roles, as you can see, to try to speed things up, but it is still painfully slow comparatively. I don't want to continue down this refactoring path if it ultimately isn't going to pan out.
Is there a way to have the best of both worlds? Ideally, I would like to do the following:
log in once at the beginning of the fixture
stay on the page without reloading
iterate through all the relevant selectors
continue iterating even if an individual test fails
TestCafe reloads a page before every test to avoid indeterministic behavior caused by mutual influence of tests on one another. However, there is an experimental and undocumented feature that disables this mechanism. In your case, you can try using the fixture.disablePageReloads method as follows:
fixture `Advanced Account Manager`
.page `https://app.wistia.io/logout`
.disablePageReloads
.beforeEach(async (t) => {
await t
.useRole(advAccountManager);
});
Please, use it at your own risk.
Another way is to collect selectors of all non-existing elements into array and check its lenght.
For example:
import { Selector } from 'testcafe';
fixture `Log all requests`
.page`https://devexpress.github.io/testcafe/example/`;
test('Test 1', async t => {
const selectors = [
{
name: 'Remote testing',
selector: Selector('label').withText('Support for testing on remote devices')
},
{
name: 'Reuse JS code',
selector: Selector('label').withText('Re-using existing JavaScript code for testing')
},
{
name: 'Background parallel testing',
selector: Selector('label').withText('Running tests in background and/or in parallel')
}
];
const assertions = await Promise.all(selectors.map(async item => ({ name: item.name, exists: await item.selector.exists })));
const nonExistingItems = assertions.filter(item => !item.exists).map(item => item.name);
await t.expect(nonExistingItems.length).eql(0, `This items should exist: ${nonExistingItems.join(', ')}. `);
});

Categories

Resources