How to interact with ag-Grid using TestCafe - testing

I want to interact with ag-Grid data using TestCafe without any framework like Mocha, Jasmine etc, is there any way?
Any help would be appreciated.
Thanks in advance.

I checked the ag-Grid demo page and it works properly with TestCafe:
import { Selector } from 'testcafe';
fixture `Fixture`
.page `https://www.ag-grid.com/example.php`;
test('test', async t => {
const filterInput = Selector('#myGrid > div > div.ag-root-wrapper-body.ag-layout-normal.ag-focus-managed > div.ag-root.ag-unselectable.ag-layout-normal > div.ag-header.ag-focus-managed.ag-pivot-off > div.ag-header-viewport > div > div.ag-header-row.ag-header-row-floating-filter > div:nth-child(1) > div.ag-floating-filter-body > div > input');
const selectAllCheckbox = Selector('#ag-input-id-63');
const cellTonySmith = Selector('#myGrid').find('span').withText('Tony Smith');
const checkboxTonySmith = cellTonySmith.parent().child(1);
const cellTonyGunner = Selector('#myGrid').find('span').withText('Tony Gunner');
const checkboxTonyGunner = cellTonyGunner.parent().child(1);
await t
.typeText(filterInput, 'Tony')
.hover(cellTonySmith)
.click(checkboxTonySmith)
.hover(cellTonyGunner)
.click(checkboxTonyGunner);
await t
.debug();
});
UPD:
I want to click on the name that belongs to English language
import { Selector } from 'testcafe';
fixture `Fixture`
.page `https://www.ag-grid.com/example.php`;
test('test', async t => {
const englishCells = Selector('div').withAttribute('col-id', 'language').withText('English');
const firstEnglishCell = englishCells.nth(0);
const nameRelatedToFirstEnglishCell = firstEnglishCell.parent().child(0).child(0).child(-1);
const secondEnglishCell = englishCells.nth(1);
const nameRelatedToSecondEnglishCell = secondEnglishCell.parent().child(0).child(0).child(-1);
await t
.click(nameRelatedToFirstEnglishCell)
.click(nameRelatedToSecondEnglishCell)
.debug();
});

Related

Why the slice method doesn't work on array prop?

I have the following code which defines a Pinia storage:
import { ref, computed, shallowRef } from 'vue'
import { defineStore } from 'pinia'
export const usePokemonStore = defineStore('pokemons', () => {
// define the pokemons list state
const pokemonsList = ref([]);
const pokemonsLoaded = ref([]);
const pokemonsLoadedNames = ref([]);
// computed
const pokemonsListLength = computed(() => pokemonsList.value.length)
const pokemonsLoadedLength = computed(() => pokemonsLoaded.value.length)
// actions
async function getList() {
const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=100000&offset=0');
const data = await res.json();
pokemonsList.value = data["results"];
}
async function loadPokemon(name) {
const URI = `https://pokeapi.co/api/v2/pokemon/${name}`
const res = await fetch(URI);
const data = await res.json();
pokemonsLoadedNames.value.push(data["name"])
pokemonsLoaded.value.push(data)
}
async function loadPokemons(offset, limit){
// basic check for limits
limit = limit > pokemonsListLength ? pokemonsListLength : limit;
limit = limit < 0 ? 10 : limit
// basic check for offset
offset = offset < 0 ? 0 : offset;
offset = offset > pokemonsListLength ? 0 : offset
for (let i = offset; i < offset+limit; i++){
// if the pokemon is already loaded skips the request for it
if (pokemonsLoadedNames.value.includes(pokemonsList.value[i].name)) {
continue;
}
// requests the pokemon given a name
loadPokemon(pokemonsList.value[i].name)
}
}
return {
pokemonsList,
pokemonsLoaded,
pokemonsListLength,
pokemonsLoadedLength,
pokemonsLoadedNames,
getList,
loadPokemon,
loadPokemons
}
})
And I have the following component which makes use of that storage to get the pokemons:
<template>
<div class="pokedex">
<PokemonImage class="pokemon-figure" pokemon="" />
<ul v-if="pokemonsToShow" class="pokemon-showcase">
<li class="pokemon-item" v-for="pokemon in pokemonsToShow">
<PokemonCard :pokemon="pokemon" />
</li>
</ul>
<div class="navigation">
<button v-show="page !== 1" #click="pageChange(-1)">Previous Page</button>
<button #click="pageChange(1)">Next Page</button>
</div>
{{ page }}
</div>
</template>
<script setup>
import { onBeforeMount, ref, computed, watch } from 'vue';
import { usePokemonStore } from '../stores/pokemon'
import PokemonCard from '../components/PokemonCard.vue'
import PokemonImage from '../components/PokemonImage.vue'
const pokeStore = usePokemonStore();
const page = ref(1)
const pokemonsToShow = ref([])
// offset and limit calculate based on the page
const limit = computed(() => 20 );
const offset = computed(() => page.value * limit.value - limit.value);
// initial load
onBeforeMount(async () => {
await pokeStore.getList()
await pokeStore.loadPokemons(0, limit.value)
pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(0, pokeStore.pokemonsLoadedLength)
})
const pageChange = async (step) => {
page.value = page.value + step
await pokeStore.loadPokemons(offset.value, limit.value)
const start = offset.value;
const end = offset.value + limit.value;
console.log(start, end)
console.log(pokeStore.pokemonsLoaded)
pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(start, end)
console.log(pokemonsToShow.value)
}
</script>
Now when the user clicks on the page button the page.value is updated so that the computed values for the offset and the limit are also updated (in reality only the offset updates) that way if the page is new I can load new pokemons from that which I do by calling the pokeStore.loadPokemons(offset.value, limit.value) function and awaiting for that inside the pageChange function. But now I want to change the pokemonsToShow so I want to get a slice of the array of loaded pokemons in the storage but every time I try to slice that array I get back nothing, even though when I print the array using console.log(pokeStore.pokemonsLoaded) the array shows as updated with the new values, and the ranges are correct.
I'm expecting the array to slice correctly since if I put static values in this function call:
pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(2, 4)
}
It works for some reason, but not with the values calculated dinamically
This is a tricky thing about console.log().
console.log(pokeStore.pokemonsLoaded) will show you the result of the fetched data even if console.log is in reality executed before the fetch is done. This is due to the fact that many browsers show a "live" view of object data.
https://developer.mozilla.org/en-US/docs/Web/API/Console/log#logging_objects
Don't use console.log(obj), use console.log(JSON.parse(JSON.stringify(obj))) ... many browsers provide a live view that constantly updates as values change. This may not be what you want.
It is probable then that the array has not actually been updated at the time you slice it. I also believe this is true because even though you await this call: await pokeStore.loadPokemons(...), that function does not await it's call to loadPokemon(). Since there is no await, the function immediately finishes executing before the fetch has finished and returns to your component code.
I believe if you do await that call, everything should start working
async function loadPokemons(offset, limit){
.
.
.
await loadPokemon(pokemonsList.value[i].name)
}

TestCafe - Can You Pass ctx (Context) Variables to reporter?

I would like to know if I have a context variable like t.ctx.data, is there a way to get that to write the value of t.ctx.data to the TestCafe JSON reporter (or any reporter)?
My code:
// Called within Express.js by a request coming from req
const testMySite = (req, res) => {
process.env.PARAMS = JSON.stringify(req.body)
let testcafe = null;
console.log(`Running test on ports 1341 and 1342`)
createTestCafe('localhost', 1341, 1342, void 0, true)
.then(tc => {
testcafe = tc;
const runner = testcafe.createRunner()
return runner
.src(`${path.dirname(__filename)}/tests/gisTest.js`)
.browsers('firefox:headless')
.reporter('json', 'report.json')
.run()
})
.then(failedCount => {
testcafe.close()
})
res.json({message: `Success! Scraper has begun to process ${req.body}`});
}
My test code:
import { ClientFunction, Selector } from 'testcafe';
const doc = process.env.PARAMS
const newDoc = JSON.parse(process.env.PARAMS)
console.log(`newDoc (from test)`, newDoc)
// const _id = newDoc._id
let data = newDoc.mydata
fixture `My Fixture`
.page('https://www.mysite.co')
.afterEach(async t => {
await t
// how do I get t.ctx.myData into the reporter??
console.log(`t.ctx.myData: `, t.ctx.myData)
})
test(`My Test`, async t => {
const photoIcon = Selector('div#sbtc div.LM8x9c > span')
const photoFieldForPaste = Selector('input#Ycyxxc')
const searchByImageButton = Selector('td#aoghAf > input')
const targetElement = Selector('div#jHnbRc span:nth-child(2) > a')
await t
.wait(1000)
.click(photoIcon)
.typeText(photoFieldForPaste, data, {paste: true})
.click(searchByImageButton)
if(await targetElement.exists && await targetElement.visible) {
await t.ctx.finalData = targetElement.innerText;
}
await t.ctx.finalData = null;
})
Please see the part // how do I get t.ctx.myData into the reporter??.
I am assuming this is the only place where I could potentially get the data from the test into the reporter but I'm not sure exactly how.
If you know how to get the t.ctx.myData variable as shown in the above code to be written to the JSON reporter, I would highly appreciate it.
Even better would be to have a way to send the t.ctx.myData value into the response.
At present, you can add only static metadata to tests and fixtures. This metadata is available in reports. Please refer to the following article to get details: https://devexpress.github.io/testcafe/documentation/guides/basic-guides/organize-tests.html#specify-test-metadata
As for sending dynamic data to the reporter, we keep this feature in mind, however we cannot give any estimates on this. Please track the following issue: https://github.com/DevExpress/testcafe/issues/3584

How to assert the values in a downloaded file using Cypress

I am downloading a zip file which has a json zipped. Using cy.readfile, I am able to read the content but I am not sure what commands can be used to assert on the values inside.
(Please let me know if there is a way to unzip the file before reading)
I need to verify I have 3 objectids present in the json and also some values of the elements.
I tried the below approach, but it did not work.
cy.readFile(`/Users/${username}/Downloads/${fileName}.zip`)
.should('contain','objectid').and('have.length',3);
The above command did not work for me :(
Could someone help me with some examples? I am new to cypress and coding,therefore struggling a little.
You can change the download folder in every test case!!
Look into your index.js in -> cypress -> plugins -> index.js and write this :
module.exports = (on, config) => {
on('before:browser:launch', (browser, options) => {
const downloadDirectory = 'C:\\downloads\\'; // this is the path you want to download
options.preferences.default['download'] = { default_directory: downloadDirectory };
return options;
});
};
Do it like this
cy.readFile(`/Users/${username}/Downloads/${fileName}.zip`)
.then((data) => {
// you can write whatever assertions you want on data
debugger;
console.log(data);
expect(data).to....
})
You can put debugger as above and logs to check what data contains and then assert
Use this link to know about available assertions https://docs.cypress.io/guides/references/assertions.html#BDD-Assertions
So here is the approach I am following.It is quite lengthy, but still posting as it might be helpful for someone.Please comment if you have any suggestions for improvements here.
I am using npm-unzipper to unzip the downloaded file.
Step 1: $ npm install unzipper
Step 2:In plugins > index.js
const fs = require('fs');
const os = require('os');
const osplatform = os.platform();
const unzipper = require('unzipper');
const userName = os.userInfo().username;
let downloadPath =`/${userName}/Downloads/`;
if (osplatform == 'win32'){
downloadPath = `/Users/${userName}/Downloads/`;
}
on('task', {
extractzip(zipname) {
const zipPath = downloadPath + zipname;
if (fs.existsSync(zipPath)) {
const readStream = fs.createReadStream(zipPath);
readStream.pipe(unzipper.Extract({path: `${downloadPath}`}));
const jsonname = 'testfile.json'
const jsonPath = downloadPath + jsonname;
return jsonPath;
}
else{
console.error('file not downloaded')
return null;
}
}
})
Step 3:support > commands.js
Cypress.Commands.add('comparefiles', { prevSubject: false }, (subject, options = {}) => {
cy.task('extractzip', 'exportfile.zip').then((jsonPath) => {
cy.fixture('export.json').then((comparefile) => {
cy.readFile(jsonPath).then((exportedfile) => {
var exported_objectinfo = exportedfile.objectInfo;
var compare_objectinfo = comparefile.objectInfo;
var exported_metaInfo = exportedfile.metaInfo;
var compare_metaInfo = comparefile.metaInfo;
expect(exported_objectinfo).to.contain.something.like(compare_objectinfo)
expect(exported_metaInfo).to.have.deep.members(compare_metaInfo)
})
})
});
});
Step 4: specs > exportandcompare.js
cy.get('[data-ci-button="Export"]').click();
cy.comparefiles();

Testcafe custom reporter doesn't return from this.formatError

I'm trying to implement a custom reporter for testcafe. If there is an error in testcase and this.formatError is called, it is not returning from this.formatError. Just hangs there indefinitely, I need to manually ctrl-c to stop the testcafe process. But if I remove this.formatError and try again it is working. What could be the reason?
Below is the code for reportTestDone()
reportTestDone (name, testRunInfo, meta) {
const errors = testRunInfo.errs;
const warnings = testRunInfo.warnings;
const hasErrors = !!errors.length;
const hasWarnings = !!warnings.length;
const result = hasErrors ? this.chalk.red('failed')
: this.chalk.green('passed');
const title = `${result} ${name} # ${meta.page}`;
this.write(title)
.newline();
if (hasErrors) {
this.write('Errors:')
.newline();
errors.forEach((error, idx) => {
this.setIndent(4)
.write(this.formatError(error, `${idx + 1} `)) //<-- this line is the problem
.write(error.errMsg)
.newline();
});
this.setIndent(0);
}
if (hasWarnings) {
this.newline()
.write('Warnings:');
warnings.forEach(warning => {
this.newline()
.write(warning);
});
}
this.setIndent(0);
}

testcafe accessing li elements

I need help in accessing the li elements in the below link.
https://www.healthdirect.gov.au/medicines/brand/amt,934621000168103/l-arginine-rch
My li elements under document.querySelectorAll('#disclaimer+section li')
I tried,
const seeAlsoElements = Selector( () => {
const seeA = document.querySelectorAll('#disclaimer+section li');
return seeA;
});
const seeAlso = await seeAlsoElements();
actualSeeAlsoFirstLine = seeAlso[0].innerText().split(':');
aSADAlink = seeAlsoElements[1].child('a').getAttribute('href');
genericVsBrandArticle = seeAlsoElements[2].getAttribute('href');
but I am getting errors. Please help me in correcting this code. I need to individually access the li tags for their href or inner text;
Your code should look like this:
const seeAlsoItems = Selector('main')
.find('footer')
.find('section')
.find('h2').withText('See also')
.sibling('ul')
.find('li');
const arginineLink = seeAlsoItems.nth(0).find('a');
await t
.expect(arginineLink.getAttribute('href'))
.eql('https://www.healthdirect.../arginine', {timeout: 10000});