I have a utility command in cypress:
Cypress.Commands.add('generateDummyText', (length: number, delay?: number) => {
const wordLength = 5;
const lorem = new LoremIpsum({
wordsPerSentence: {
max: wordLength,
min: wordLength,
},
words: ['word1', 'word2', 'word3', 'word4', 'word5'],
});
const words = lorem.generateWords(Math.ceil(length / wordLength));
cy.wrap(words).as('dummyText');
});
it('test', () => {
// Generate dummy text
cy.generateDummyText(280);
// I want to type the "dummyText variable here"
cy.get('myinput').type()
});
How can this be done? I don't need to use a custom cypress command, but I'd prefer to use one. Looking forward to your reply!
You can access it just by using:
cy.type(this.dummyText)
Another option is just to use faker to generate the random words for you.
Add the faker module to you project, then you can just do:
const faker = require("faker");
.type(faker.random.words(5));
instead of using a custom command for it
You can get the value either by alias:
cy.generateDummyText(280);
cy.get("#dummyText").then(dummyText => {
cy.get('myinput').type(this.dummyText)
})
or directly by the command return value:
cy.generateDummyText(280).then(dummyText => {
cy.get('myinput').type(this.dummyText)
})
Related
I am getting this error when trying to access a cypress task masking the "xlsx": "^0.18.5"
for reading excel files.
From Node.js Internals:
TypeError: f.slice is not a function
at firstbyte (/local0/biologics/gitcheckouts/new-ui-e2e/node_modules/xlsx/xlsx.js:23626:38)
at readSync (/local0/biologics/gitcheckouts/new-ui-e2e/node_modules/xlsx/xlsx.js:23706:14)...
My task looks like this cypress.config.ts
on('task', {
readXlsx: readXlsx.read,
});
If I add brackets after the read:-> readXlsx: readXlsx.read() it already fails when starting cypress with the same error message:
Does anybody know what to do? (Cypress version 12.5.0)
Add on:
import * as fs from 'fs';
private validateExcelFile(countedItems: number, correction: number) {
cy.get('#LASTDOWNLOADEDFILE').then((name) => {
const fileName = name as unknown as string;
cy.log(`Validating excel file: ${fileName}`);
const buffer = fs.readFileSync(fileName);
cy.task('readXlsx', { buffer }).then((rows) => {
const rdw = (rows as string).length;
expect(rdw).to.be.equal(countedItems - correction);
});
});
}
I cannot tell what code, if any, precedes the task. The message seems to indicate a buffer issue, here is my working code you can compare to your own.
Otherwise, suspect the file itself.
import { readFileSync } from "fs";
import { read } from "xlsx/xlsx.mjs";
function read(name) {
const buffer = readFileSync(name);
const workbook = read(buffer);
return workbook
}
...
on('task', {
readXlsx: (name) => read(name)
...
sorry I am new to cypress
I got a large txt file, it has 5000 lines of txt
all txt is divided by \n
12331565399
29165910115
58108651482
74656524192
70536463673
11606518282
15616508033
and more...
I stored this txt file in my fixtures
and in my e2e cy, I wrote
cy.readFile('./cypress/fixtures/list.txt')
it gives me all the txt file but I don't know how to pick a random txt from that file
please help me
You can do it without converting the 5000 lines into properly formatted JSON, by adding some processing after reading the file
cy.readFile('./cypress/fixtures/list.txt')
.then(list => {
const strings = list.split('\n') // convert to array
.map(line => line.replace('\r', '')) // depending on txt file format,
// may need to remove "\r" character
const randomText = Cypress._.sample(strings)
return randomText
})
.then(randomText => {
...
It would be easier to convert the fixture file to JSON and then from there you have three ways to read the file, all of which will be using the lodash _.sample() method to pick at random.
Using require:
const textArrayFromRequire = require('../fixtures/list.json')
it('use require', function() {
const randomTextFromRequire = Cypress._.sample(textArrayFromRequire)
cy.wrap(randomTextFromRequire).should('be.oneOf', textArrayFromRequire)
})
Using import:
import textArrayFromImport from '../fixtures/list.json'
it('use import', function() {
const randomTextFromImport = Cypress._.sample(textArrayFromImport)
cy.wrap(randomTextFromImport).should('be.oneOf', textArrayFromImport)
})
Using cy.fixture():
it('use cy.fixture', function() {
cy.fixture('list.json').then(textArrayFromFixture => {
const randomTextFromFixture = Cypress._.sample(textArrayFromFixture)
expect(randomTextFromFixture).to.be.oneOf(textArrayFromFixture)
})
})
Here is a working example.
I have this URL :
https://www.acme.com/book/passengers?id=h1c7cafc-5457-4564-af9d-2599c6a37dde&hash=7EPbMqFFQu8T5R3AQr1GCw>msearchtype=City+Break
and want to store these values :
id=h1c7cafc-5457-4564-af9d-2599c6a37dde
hash=7EPbMqFFQu8T5R3AQr1GCw
for use in a later test.
How do I extract these values from the URL? I am using Cypress. Thanks.
Please follow the following steps and that's all there is to it.
You can put this snippet into before() hooks of your spec file and you can access them wherever you want.
cy.location().then(fullUrl => {
let pathName = fullUrl.pathname
let arr = pathName.split('?');
let arrayValues = arr[1].split('&');
cy.log(arrayValues[0]);
cy.log(arrayValues[1]);
cy.log(arrayValues[2]);
})
In case anyone needs the correct answer, use the cy.location('search') to extract the search part of the location data.
Then for convenience, convert it to a javascript object with key/value pairs for each item.
Finally, store it in a Cypress alias to use later in the test.
cy.location('search')
.then(search=> {
const searchValues = search.split('?')[1].split('&')
// yields: [
// id=h1c7cafc-5457-4564-af9d-2599c6a37dde,
// hash=7EPbMqFFQu8T5R3AQr1GCw,
// gtmsearchtype=City+Break
// ]
const searchMap = searchValues.reduce((acc,item) => {
const [key,value] = item.split('=')
acc[key] = value.replace('+', ' ')
return acc
}, {})
// yields: {
// id: "h1c7cafc-5457-4564-af9d-2599c6a37dde",
// hash: "7EPbMqFFQu8T5R3AQr1GCw",
// gtmsearchtype: "City Break"
// }
cy.wrap(searchMap).as('searchMap')
})
Using #Srinu Kodi's answer I got it working changing ...then(fullUrl => ... to
...then((fullUrl) => ...
I can't figure out why Jasmine is claiming that the function I'm spying on isn't being called, especially since it is logging in buildLinksObj when called through and not calling when I remove .and.callThrough() I feel like I've written similar code a bunch of times before without any problem. I'm using Jasmine 2.9
The error message I'm getting is:
1) addToLinks should call buildLinksObj if its given an object with children
it should add the personalized links to PageApp.meta.analytics.links
Expected spy buildLinksObj to have been called.
at UserContext.<anonymous> (http://localhost:9877webpack:///tests/specs/common/FetchPersonalContent.spec.js:854:0 <- tests/app-mcom.js:104553:48)
Here's the except of my code:
FetchPersonalContent.js
const buildLinksObj = (responseObj = {}, targetObj, PageApp) => {
console.log('it logs in buildLinksObj') // This is logging!
}
const addToLinks = (responseArr, personalizedLinks) => {
responseArr.forEach((media) => {
const type = media.type;
const typeObj = media[type];
buildLinksObj(typeObj, personalizedLinks, PageApp);
if (typeObj && typeObj.children) {
console.log('has children!')
console.log('typeObj.children is: ', typeObj.children);
typeObj.children.forEach((child) => {
console.log('has a child')
buildLinksObj(child, personalizedLinks, PageApp);
console.log('buildLinksObj was definitely called. what the heck?')
});
}
});
}
export {buildLinksObj, addToLinks, FetchPersonalContent as default,
};
FetchPersonalContent.spec.js
import * as FetchPersonalContent from '../../../src/FetchPersonalContent'; // my path is definitely correct
describe('it should add the personalized links to PageApp.meta.analytics.links', () => {
it('addToLinks should call buildLinksObj if its given an object with children ', () => {
spyOn(FetchPersonalContent, 'buildLinksObj').and.callThrough();
FetchPersonalContent.addToLinks([{
"personalId": 30718,
"type": "carousel",
"carousel": {}
}], {});
expect(FetchPersonalContent.buildLinksObj).toHaveBeenCalled();
});
});
I'd really appreciate any help!
I have a feeling FetchPersonalContent.buildLinksObj in the spec file is not pointing to the same instance as buildLinksObj in the FetchPersonalContent.js file.
Why is export {FetchPersonalContent as default} required? I am assuming you have shared the complete content of FetchPersonalContent.js in your question.
Possible solutions:
You can try removing FetchPersonalContent from the export statement.
Or
Instead of
export {buildLinksObj, addToLinks, FetchPersonalContent as default,
};
You can directly export the constants in FetchPersonalContent.js file.
In Cypress, the select('option-text') command will only work if there is an exact match. How can I tell it to select an option that contains the text instead ?
Through aliasing you can make it work:
cy.get('select')
.find('option')
.contains('YOUR TEXT')
.as('selectOption')
.then( () => {
cy.get('select')
.select(`${this.selectOption.text()}`)
})
A slightly improved variant of Can Akgun user is as following (bonus adding as cypress command):
/**
* Select an option containing part of string in its text body
* {String} elementSelector
* {String} optionTextPart
*/
Cypress.Commands.add('selectOptionContaining', (elementSelector, optionTextPart) => {
cy.get(elementSelector)
.find('option')
.contains(optionTextPart)
.then($option => {
cy.get(elementSelector).select($option.text());
});
});
In this way we do not need global variables.
I haven't found anything like that in the api so far, nor in the github issues.
So I resorted to adding a custom command in my project:
// cypress/support/commands.ts
Cypress.Commands.add('selectContaining', {prevSubject: 'element'}, (subject, text, options) => {
return cy.wrap(subject).contains('option', text, options).then(
option => cy.get('select#report-selection').select(option.text().trim())
);
});
// cypress/support/commands_type.ts
declare namespace Cypress {
interface Chainable<Subject = any> {
requestApi(method: HttpMethod, url: string, body?: RequestBody): Chainable<Cypress.Response>;
selectContaining(text: string | string[], options?: Partial<SelectOptions>): Chainable<Subject>;
}
}