Estoy tratando de establecer una variable dentro de un comando .then() que se declara fuera de él, y después de que finaliza todo el bloque (el .then()) devuelvo ese valor.
El problema es que, cuando devuelvo el valor, la variable no está definida, pero dentro del bloque .then(), la variable está cargada.
Aquí está el código de ejemplo:
public getValueFromElement(): string { cy.log("Obtaining the Value"); let myNumber: string; // Here I'm declaring my variable cy.get(this.labelWithText).then(($element) => { let originalLabelText: string = $element.text(); let splittedText: string[]; splittedText = originalLabelText.split(": "); myNumber = splittedText[1]; // Here I'm assigning the value cy.log("Inside the THEN" + myNumber); //This logs the number correctly }); return myNumber; // But after I return it using the function, the value is `undefined`! } Supongo que esto podría estar relacionado con el problema asíncrono / sincronizado, ya que la declaración de return se ejecuta inmediatamente cuando se llama a la función, y la promesa creada por .then() todavía se está ejecutando, pero no sé cómo para arreglar esto.
¿Sabes cómo puedo esperar a que .then() termine primero antes de devolver el valor?
¡¡Gracias!!
Dices "El problema es que, cuando devuelvo el valor, la variable no está definida".
Esto se debe a que la línea return myNumber se ejecuta antes de que se cy.get(this.labelWithText).then(($element) => { , porque el comando se ejecuta de forma asíncrona.
Debe devolver el comando en sí, y también el myNumber derivado se devuelve desde el interior de .then() .
public getValueFromElement(): Chainable<string> { // cannot return the raw string cy.log("Obtaining the Value"); return cy.get(this.labelWithText).then(($element) => { ... const myNumber = splittedText[1]; cy.log("Inside the THEN " + myNumber) return myNumber }) }úsalo así
getValueFromElement().then(myNumber => { cy.log("Outside the function " + myNumber) })Puedes hacerlo sincrónicamente así
public getValueFromElement(): string { cy.log("Obtaining the Value"); const $element = Cypress.$(this.labelWithText) const originalLabelText: string = $element.text() const splitText = originalLabelText.split(": ") const myNumber = splitText[1] return myNumber }Aquí sacrifica las opciones de reintento que están integradas en los comandos asincrónicos.
Cypress dice que lo use solo si está seguro de que el elemento ya existe, lo que depende del contexto de su texto.
@MikhailBolotov de hecho. Así es como manejarías eso
cy.get("myOpenElementSelector").click() // async code .then(() => { // must wrap sync code in then const myNumber = getValueFromElement() // to ensure correct sequence expect(+myNumber).to.eq(64) })@Mihi tiene la forma idomática, pero a veces es difícil al componer métodos de objetos de página.
He llegado a la conclusión de que esto funciona:
public async getTheNumber(): Promise<string> { return new Promise((resolve, reject) => { cy.log("Retrieving the number"); cy.get(this.selector).then(($element) => { let myNumber = $element.text().split(": ")[1]; cy.log(`The Number is ${myNumber}`); resolve(myNumber); }); }); }y al leerlo de la prueba estoy haciendo esto:
myNumberAtTestLevel = await myObject.getTheNumber(); La cosa es que he visto que tengo que cambiar mi método it() a async para que esto funcione.
Sin embargo, me encontré con esta documentación de Cypress: https://docs.cypress.io/api/utilities/promise#Syntax
Estoy tratando de implementar lo mismo usando Cypress. Cypress.Promises pero no puedo.
¿Algunas ideas?