diff --git a/examples/angular/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts b/examples/angular/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts index 984a6bb0..fca9ee88 100644 --- a/examples/angular/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts +++ b/examples/angular/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts @@ -10,6 +10,7 @@ export class PokemonPageDriver { this.helper.beforeAndAfter(); this.pokemonDriver.beforeAndAfter(); }; + given = { fetchPokemonResponse: (response: PokemonList) => this.helper.given.interceptAndMockResponse({ @@ -27,14 +28,12 @@ export class PokemonPageDriver { }; when = { - ...this.pokemonDriver.when + ...this.pokemonDriver.when, + waitForPokemonLastCall: () => this.helper.when.waitForLastCall("pokemon") }; get = { ...this.pokemonDriver.get, - fetchPokemonOffset: () => { - this.helper.when.waitForLastCall("pokemon"); - return this.helper.get.requestQueryParam("pokemon", "offset"); - } + fetchPokemonQueryParams: () => this.helper.get.requestQueryParams("pokemon") }; } diff --git a/examples/angular/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts b/examples/angular/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts index 6de04f7c..143789fe 100644 --- a/examples/angular/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts +++ b/examples/angular/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts @@ -75,4 +75,40 @@ describe("Pokemon e2e", () => { }); }); }); + + describe("when typing pokemon index and clicking Go", () => { + beforeEach(() => { + when.pokemon.pokemonGo.typePokemonIndex("25"); + when.pokemon.pokemonGo.clickGo(); + when.waitUntil(() => get.elementByText("pikachu")); + }); + + it("should update index", () => { + then(get.pokemon.countText()).shouldStartWith("25 of"); + }); + + it("should update pokemon image", () => { + then(get.pokemon.image.pictureSrc()).shouldEndWith("/25.gif"); + }); + + it("prev button should be enabled", () => { + then(get.pokemon.prevButton()).shouldBeEnabled(); + }); + + it("should render pokemon name", () => { + then(get.elementByText("pikachu")).shouldExist(); + }); + }); + + describe("when changing from pokemon without gif to pokemon with gif, should show gif", () => { + it("should render pokemon gif", () => { + when.pokemon.pokemonGo.typePokemonIndex("888"); + when.pokemon.pokemonGo.clickGo(); + when.waitUntil(() => get.elementByText("zacian")); + when.pokemon.pokemonGo.typePokemonIndex("33"); + when.pokemon.pokemonGo.clickGo(); + when.waitUntil(() => get.elementByText("nidorino")); + then(get.pokemon.image.pictureSrc()).shouldEndWith("/33.gif"); + }); + }); }); diff --git a/examples/angular/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts b/examples/angular/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts index 9e36ba9e..7019b528 100644 --- a/examples/angular/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts +++ b/examples/angular/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts @@ -19,6 +19,7 @@ describe("Pokemon Page integration Tests", () => { given.pokemon.fetchPokemonResponse(pokemonList); given.pokemon.fetchImageResponse("default.png"); when.visit("/"); + when.pokemon.waitForPokemonLastCall(); }); it("should disable next button once showing last pokemon", () => { @@ -28,5 +29,15 @@ describe("Pokemon Page integration Tests", () => { it("should disable prev button once showing first pokemon", () => { then(get.pokemon.prevButton()).shouldBeDisabled(); }); + + it("should render correct image", () => { + then(get.pokemon.image.pictureSrc()).shouldEndWith("/1.gif"); + }); + + it("should fetch pokemon by index", () => { + when.pokemon.pokemonGo.typePokemonIndex("78"); + when.pokemon.pokemonGo.clickGo(); + then(get.pokemon.fetchPokemonQueryParams()).shouldInclude({ offset: "77" }); + }); }); }); diff --git a/examples/angular/pokemon-catalog/src/app/components/pokemon-catalog/pokemon-catalog.component.spec.cy.ts b/examples/angular/pokemon-catalog/src/app/components/pokemon-catalog/pokemon-catalog.component.spec.cy.ts index 5a7ee5d0..fb5c3b37 100644 --- a/examples/angular/pokemon-catalog/src/app/components/pokemon-catalog/pokemon-catalog.component.spec.cy.ts +++ b/examples/angular/pokemon-catalog/src/app/components/pokemon-catalog/pokemon-catalog.component.spec.cy.ts @@ -1,3 +1,4 @@ +import { PokemonGoComponent } from "@components/pokemon-go/pokemon-go.component"; import { PokemonList, PokemonService } from "@services/pokemon.service"; import { then } from "@shellygo/cypress-test-utils"; import { Builder } from "builder-pattern"; @@ -11,7 +12,7 @@ describe("PokemonCatalogComponent Tests", () => { const { when, given, get, beforeAndAfter } = new PokemonCatalogComponentDriver(); const testConfig = { - declarations: [PokemonCatalog, PokemonImageComponent], + declarations: [PokemonCatalog, PokemonImageComponent, PokemonGoComponent], providers: [ { provide: PokemonService, diff --git a/examples/angular/pokemon-catalog/src/app/components/pokemon-go/pokemon-go.component.driver.ts b/examples/angular/pokemon-catalog/src/app/components/pokemon-go/pokemon-go.component.driver.ts index cdc091b9..0eed78ef 100644 --- a/examples/angular/pokemon-catalog/src/app/components/pokemon-go/pokemon-go.component.driver.ts +++ b/examples/angular/pokemon-catalog/src/app/components/pokemon-go/pokemon-go.component.driver.ts @@ -1,9 +1,34 @@ +import type { Type } from "@angular/core"; +import { CypressHelper } from "@shellygo/cypress-test-utils"; +import { CypressAngularComponentHelper } from "@shellygo/cypress-test-utils/angular"; +import { MountConfig } from "cypress/angular"; +import { PokemonGoComponent } from "./pokemon-go.component"; + export class PokemonGoComponentDriver { - beforeAndAfter = () => {}; + private helper = new CypressHelper({ defaultDataAttribute: "data-hook" }); + private angularComponentHelper = new CypressAngularComponentHelper(); + + private componentProperties: Partial = {}; + + beforeAndAfter = () => { + this.helper.beforeAndAfter(); + }; given = {}; - when = {}; + when = { + render: (type: Type, config: MountConfig) => { + this.angularComponentHelper.when.mount(type, config, { + ...this.componentProperties + }); + }, + typePokemonIndex: (value: string) => this.helper.when.type("pokemon-index", value), + clickGo: () => this.helper.when.click("go") + }; - get = {}; + get = { + pokemonIndexInputValue: () => this.helper.get.inputValue("pokemon-index"), + selectedPokemonSpy: () => this.helper.get.spy("selectedPokemon"), + goButton: () => this.helper.get.elementByTestId("go") + }; } diff --git a/examples/angular/pokemon-catalog/src/app/components/pokemon-go/pokemon-go.component.spec.cy.ts b/examples/angular/pokemon-catalog/src/app/components/pokemon-go/pokemon-go.component.spec.cy.ts index 3ffd5697..b79b0303 100644 --- a/examples/angular/pokemon-catalog/src/app/components/pokemon-go/pokemon-go.component.spec.cy.ts +++ b/examples/angular/pokemon-catalog/src/app/components/pokemon-go/pokemon-go.component.spec.cy.ts @@ -1 +1,48 @@ -describe("PokemonGo Component Tests", () => {}); +import { FormsModule } from "@angular/forms"; +import { then } from "@shellygo/cypress-test-utils"; +import { PokemonGoComponent } from "./pokemon-go.component"; +import { PokemonGoComponentDriver } from "./pokemon-go.component.driver"; + +describe("PokemonGo Component Tests", () => { + const testConfig = { + declarations: [PokemonGoComponent], + imports: [FormsModule] + }; + + const { when, get, given, beforeAndAfter } = new PokemonGoComponentDriver(); + beforeAndAfter(); + + beforeEach(() => { + when.render(PokemonGoComponent, testConfig); + }); + it("Go button should be disabled", () => { + then(get.goButton()).shouldBeDisabled(); + }); + + it("when typing index Go button should be enabled", () => { + when.typePokemonIndex("33"); + then(get.goButton()).shouldBeEnabled(); + }); + + it("When input filled should have input value", () => { + when.typePokemonIndex("42"); + then(get.pokemonIndexInputValue()).shouldEqual("42"); + }); + + it("When input and clicked go should fetch pokemon by index", () => { + when.typePokemonIndex("12"); + when.clickGo(); + then(get.selectedPokemonSpy()).shouldHaveBeenCalledWith("12"); + }); + + it("should clear input when clicking submit", () => { + when.typePokemonIndex("33"); + when.clickGo(); + then(get.pokemonIndexInputValue()).shouldEqual(""); + }); + + it("should not update input value when typing non digits", () => { + when.typePokemonIndex("abcd-"); + then(get.pokemonIndexInputValue()).shouldEqual(""); + }); +}); diff --git a/examples/angular/pokemon-catalog/src/app/components/pokemon-image/pokemon-image.component.ts b/examples/angular/pokemon-catalog/src/app/components/pokemon-image/pokemon-image.component.ts index 5038a581..303f365e 100644 --- a/examples/angular/pokemon-catalog/src/app/components/pokemon-image/pokemon-image.component.ts +++ b/examples/angular/pokemon-catalog/src/app/components/pokemon-image/pokemon-image.component.ts @@ -31,6 +31,9 @@ export class PokemonImageComponent { this.showFallbackImage = true; } + ngOnChanges() { + this.showFallbackImage = false; + } getPokemonImage = () => { return `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/${this.pokemonIndex}.gif`; }; diff --git a/examples/lit/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts b/examples/lit/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts index 2eb46fa6..cbdb6c87 100644 --- a/examples/lit/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts +++ b/examples/lit/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts @@ -1,6 +1,7 @@ import { PokemonCatalogComponentDriver } from "@components/pokemon-catalog/pokemon-catalog.component.driver"; import { PokemonList } from "@services/pokemon.service"; import { CypressHelper } from "@shellygo/cypress-test-utils"; +import { Interception } from "cypress/types/net-stubbing"; export class PokemonPageDriver { private helper: CypressHelper = new CypressHelper({ defaultDataAttribute: "data-hook" }); @@ -10,7 +11,9 @@ export class PokemonPageDriver { this.helper.beforeAndAfter(); this.pokemonDriver.beforeAndAfter(); }; + given = { + ...this.pokemonDriver.given, fetchPokemonResponse: (response: PokemonList) => this.helper.given.interceptAndMockResponse({ url: "https://pokeapi.co/api/v2/pokemon**", @@ -27,10 +30,12 @@ export class PokemonPageDriver { }; when = { - ...this.pokemonDriver.when + ...this.pokemonDriver.when, + waitForPokemonLastCall: (): Cypress.Chainable => this.helper.when.waitForLastCall("pokemon") }; get = { - ...this.pokemonDriver.get + ...this.pokemonDriver.get, + fetchPokemonQueryParams: () => this.helper.get.requestQueryParams("pokemon") }; } diff --git a/examples/lit/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts b/examples/lit/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts index 6de04f7c..143789fe 100644 --- a/examples/lit/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts +++ b/examples/lit/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts @@ -75,4 +75,40 @@ describe("Pokemon e2e", () => { }); }); }); + + describe("when typing pokemon index and clicking Go", () => { + beforeEach(() => { + when.pokemon.pokemonGo.typePokemonIndex("25"); + when.pokemon.pokemonGo.clickGo(); + when.waitUntil(() => get.elementByText("pikachu")); + }); + + it("should update index", () => { + then(get.pokemon.countText()).shouldStartWith("25 of"); + }); + + it("should update pokemon image", () => { + then(get.pokemon.image.pictureSrc()).shouldEndWith("/25.gif"); + }); + + it("prev button should be enabled", () => { + then(get.pokemon.prevButton()).shouldBeEnabled(); + }); + + it("should render pokemon name", () => { + then(get.elementByText("pikachu")).shouldExist(); + }); + }); + + describe("when changing from pokemon without gif to pokemon with gif, should show gif", () => { + it("should render pokemon gif", () => { + when.pokemon.pokemonGo.typePokemonIndex("888"); + when.pokemon.pokemonGo.clickGo(); + when.waitUntil(() => get.elementByText("zacian")); + when.pokemon.pokemonGo.typePokemonIndex("33"); + when.pokemon.pokemonGo.clickGo(); + when.waitUntil(() => get.elementByText("nidorino")); + then(get.pokemon.image.pictureSrc()).shouldEndWith("/33.gif"); + }); + }); }); diff --git a/examples/lit/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts b/examples/lit/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts index 9e36ba9e..7019b528 100644 --- a/examples/lit/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts +++ b/examples/lit/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts @@ -19,6 +19,7 @@ describe("Pokemon Page integration Tests", () => { given.pokemon.fetchPokemonResponse(pokemonList); given.pokemon.fetchImageResponse("default.png"); when.visit("/"); + when.pokemon.waitForPokemonLastCall(); }); it("should disable next button once showing last pokemon", () => { @@ -28,5 +29,15 @@ describe("Pokemon Page integration Tests", () => { it("should disable prev button once showing first pokemon", () => { then(get.pokemon.prevButton()).shouldBeDisabled(); }); + + it("should render correct image", () => { + then(get.pokemon.image.pictureSrc()).shouldEndWith("/1.gif"); + }); + + it("should fetch pokemon by index", () => { + when.pokemon.pokemonGo.typePokemonIndex("78"); + when.pokemon.pokemonGo.clickGo(); + then(get.pokemon.fetchPokemonQueryParams()).shouldInclude({ offset: "77" }); + }); }); }); diff --git a/examples/lit/pokemon-catalog/src/components/pokemon-go/pokemon-go.component.driver.ts b/examples/lit/pokemon-catalog/src/components/pokemon-go/pokemon-go.component.driver.ts index cdc091b9..d4164b6c 100644 --- a/examples/lit/pokemon-catalog/src/components/pokemon-go/pokemon-go.component.driver.ts +++ b/examples/lit/pokemon-catalog/src/components/pokemon-go/pokemon-go.component.driver.ts @@ -1,9 +1,36 @@ +import { CypressHelper } from "@shellygo/cypress-test-utils"; +import { CypressLitComponentHelper } from "@shellygo/cypress-test-utils/lit"; +import { html } from "lit"; +import { PokemonGoComponent } from "./pokemon-go.component"; + export class PokemonGoComponentDriver { - beforeAndAfter = () => {}; + private helper = new CypressHelper({ defaultDataAttribute: "data-hook" }); + private litComponentHelper = new CypressLitComponentHelper(); + private props = { + onSubmit: (pokemonIndex: string) => {} + }; + beforeAndAfter = () => { + this.helper.beforeAndAfter(); + }; - given = {}; + given = { + onSubmitSpy: () => { + this.props.onSubmit = this.helper.given.spyOnObject(this.props, "onSubmit"); + } + }; - when = {}; + when = { + render: (element: PokemonGoComponent) => { + this.litComponentHelper.when.unmount(element); + this.litComponentHelper.when.mount(element, html``); + }, + typePokemonIndex: (input: string) => this.helper.when.type("pokemon-index", input), + clickGo: () => this.helper.when.click("go") + }; - get = {}; + get = { + onSubmitSpy: () => this.helper.get.spy("onSubmit"), + pokemonIndexInputValue: () => this.helper.get.inputValue("pokemon-index"), + goButton: () => this.helper.get.elementByTestId("go") + }; } diff --git a/examples/lit/pokemon-catalog/src/components/pokemon-go/pokemon-go.component.spec.cy.ts b/examples/lit/pokemon-catalog/src/components/pokemon-go/pokemon-go.component.spec.cy.ts index 3ffd5697..118d5c69 100644 --- a/examples/lit/pokemon-catalog/src/components/pokemon-go/pokemon-go.component.spec.cy.ts +++ b/examples/lit/pokemon-catalog/src/components/pokemon-go/pokemon-go.component.spec.cy.ts @@ -1 +1,44 @@ -describe("PokemonGo Component Tests", () => {}); +import { then } from "@shellygo/cypress-test-utils"; +import { PokemonGoComponent } from "./pokemon-go.component"; +import { PokemonGoComponentDriver } from "./pokemon-go.component.driver"; + +describe("PokemonGo Component Tests", () => { + const { when, given, get, beforeAndAfter } = new PokemonGoComponentDriver(); + beforeAndAfter(); + + beforeEach(() => { + given.onSubmitSpy(); + when.render(new PokemonGoComponent()); + }); + + it("Go button should be disabled", () => { + then(get.goButton()).shouldBeDisabled(); + }); + + it("when typing index Go button should be enabled", () => { + when.typePokemonIndex("33"); + then(get.goButton()).shouldBeEnabled(); + }); + + it("When input filled should have input value", () => { + when.typePokemonIndex("42"); + then(get.pokemonIndexInputValue()).shouldEqual("42"); + }); + + it("when typing index and submitting should call onSubmit", () => { + when.typePokemonIndex("33"); + when.clickGo(); + then(get.onSubmitSpy()).shouldHaveBeenCalledWith("33"); + }); + + it("should clear input when clicking submit", () => { + when.typePokemonIndex("33"); + when.clickGo(); + then(get.pokemonIndexInputValue()).shouldEqual(""); + }); + + it("should not update input value when typing non digits", () => { + when.typePokemonIndex("abcd-"); + then(get.pokemonIndexInputValue()).shouldEqual(""); + }); +}); diff --git a/examples/lit/pokemon-catalog/src/components/pokemon-image/pokemon-image.component.ts b/examples/lit/pokemon-catalog/src/components/pokemon-image/pokemon-image.component.ts index 06c945b0..fa58a57c 100644 --- a/examples/lit/pokemon-catalog/src/components/pokemon-image/pokemon-image.component.ts +++ b/examples/lit/pokemon-catalog/src/components/pokemon-image/pokemon-image.component.ts @@ -1,4 +1,4 @@ -import { LitElement, html } from "lit"; +import { LitElement, PropertyValues, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import styles from "./pokemon-image.component.scss"; @@ -14,6 +14,12 @@ export class PokemonImageComponent extends LitElement { return styles; } + override willUpdate(changedProperties: PropertyValues) { + if (changedProperties.has("pokemonIndex")) { + this.showFallbackImage = false; + } + } + onImageError = event => { this.showFallbackImage = true; }; diff --git a/examples/react/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts b/examples/react/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts index 0e5109a5..c4b9031a 100644 --- a/examples/react/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts +++ b/examples/react/pokemon-catalog/cypress/drivers/pokemon-page.driver.ts @@ -27,14 +27,12 @@ export class PokemonPageDriver { }; when = { - ...this.pokemonDriver.when + ...this.pokemonDriver.when, + waitForPokemonLastCall: () => this.helper.when.waitForLastCall("pokemon") }; get = { ...this.pokemonDriver.get, - fetchPokemonOffset: () => { - this.helper.when.waitForLastCall("pokemon"); - return this.helper.get.requestQueryParam("pokemon", "offset"); - } + fetchPokemonQueryParams: () => this.helper.get.requestQueryParams("pokemon") }; } diff --git a/examples/react/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts b/examples/react/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts index 6de04f7c..143789fe 100644 --- a/examples/react/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts +++ b/examples/react/pokemon-catalog/cypress/e2e/pokemon-page.spec.cy.ts @@ -75,4 +75,40 @@ describe("Pokemon e2e", () => { }); }); }); + + describe("when typing pokemon index and clicking Go", () => { + beforeEach(() => { + when.pokemon.pokemonGo.typePokemonIndex("25"); + when.pokemon.pokemonGo.clickGo(); + when.waitUntil(() => get.elementByText("pikachu")); + }); + + it("should update index", () => { + then(get.pokemon.countText()).shouldStartWith("25 of"); + }); + + it("should update pokemon image", () => { + then(get.pokemon.image.pictureSrc()).shouldEndWith("/25.gif"); + }); + + it("prev button should be enabled", () => { + then(get.pokemon.prevButton()).shouldBeEnabled(); + }); + + it("should render pokemon name", () => { + then(get.elementByText("pikachu")).shouldExist(); + }); + }); + + describe("when changing from pokemon without gif to pokemon with gif, should show gif", () => { + it("should render pokemon gif", () => { + when.pokemon.pokemonGo.typePokemonIndex("888"); + when.pokemon.pokemonGo.clickGo(); + when.waitUntil(() => get.elementByText("zacian")); + when.pokemon.pokemonGo.typePokemonIndex("33"); + when.pokemon.pokemonGo.clickGo(); + when.waitUntil(() => get.elementByText("nidorino")); + then(get.pokemon.image.pictureSrc()).shouldEndWith("/33.gif"); + }); + }); }); diff --git a/examples/react/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts b/examples/react/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts index 9e36ba9e..7019b528 100644 --- a/examples/react/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts +++ b/examples/react/pokemon-catalog/cypress/integration/pokemon-page.spec.cy.ts @@ -19,6 +19,7 @@ describe("Pokemon Page integration Tests", () => { given.pokemon.fetchPokemonResponse(pokemonList); given.pokemon.fetchImageResponse("default.png"); when.visit("/"); + when.pokemon.waitForPokemonLastCall(); }); it("should disable next button once showing last pokemon", () => { @@ -28,5 +29,15 @@ describe("Pokemon Page integration Tests", () => { it("should disable prev button once showing first pokemon", () => { then(get.pokemon.prevButton()).shouldBeDisabled(); }); + + it("should render correct image", () => { + then(get.pokemon.image.pictureSrc()).shouldEndWith("/1.gif"); + }); + + it("should fetch pokemon by index", () => { + when.pokemon.pokemonGo.typePokemonIndex("78"); + when.pokemon.pokemonGo.clickGo(); + then(get.pokemon.fetchPokemonQueryParams()).shouldInclude({ offset: "77" }); + }); }); }); diff --git a/examples/react/pokemon-catalog/src/components/pokemon-go/pokemon-go.driver.tsx b/examples/react/pokemon-catalog/src/components/pokemon-go/pokemon-go.driver.tsx index cdc091b9..4181f837 100644 --- a/examples/react/pokemon-catalog/src/components/pokemon-go/pokemon-go.driver.tsx +++ b/examples/react/pokemon-catalog/src/components/pokemon-go/pokemon-go.driver.tsx @@ -1,9 +1,40 @@ +import { CypressHelper } from "@shellygo/cypress-test-utils"; +import { CypressReactComponentHelper } from "@shellygo/cypress-test-utils/react"; +import type { Attributes, ReactNode } from "react"; +import { IProps, PokemonGoComponent } from "./pokemon-go"; + export class PokemonGoComponentDriver { - beforeAndAfter = () => {}; + private helper = new CypressHelper({ defaultDataAttribute: "data-hook" }); + private reactComponentHelper = new CypressReactComponentHelper(); + + private props: IProps = { + onSubmit: () => {} + }; + + beforeAndAfter = () => { + this.helper.beforeAndAfter(); + }; - given = {}; + given = { + onSubmitSpy: () => (this.props.onSubmit = this.helper.given.spy("onSubmit")) + }; - when = {}; + when = { + render: ( + type: typeof PokemonGoComponent, + props?: (Attributes & Partial) | null, + ...children: ReactNode[] + ) => { + const mergedProps: Attributes & IProps = { ...this.props, ...props }; + this.reactComponentHelper.when.mount(type, mergedProps, children); + }, + typePokemonIndex: (input: string) => this.helper.when.type("pokemon-index", input), + clickGo: () => this.helper.when.click("go") + }; - get = {}; + get = { + onSubmitSpy: () => this.helper.get.spy("onSubmit"), + pokemonIndexInputValue: () => this.helper.get.inputValue("pokemon-index"), + goButton: () => this.helper.get.elementByTestId("go") + }; } diff --git a/examples/react/pokemon-catalog/src/components/pokemon-go/pokemon-go.spec.cy.ts b/examples/react/pokemon-catalog/src/components/pokemon-go/pokemon-go.spec.cy.ts index 3ffd5697..bff4f179 100644 --- a/examples/react/pokemon-catalog/src/components/pokemon-go/pokemon-go.spec.cy.ts +++ b/examples/react/pokemon-catalog/src/components/pokemon-go/pokemon-go.spec.cy.ts @@ -1 +1,39 @@ -describe("PokemonGo Component Tests", () => {}); +import { then } from "@shellygo/cypress-test-utils"; +import { PokemonGoComponent } from "./pokemon-go"; +import { PokemonGoComponentDriver } from "./pokemon-go.driver"; + +describe("PokemonGo Component Tests", () => { + const { when, given, get, beforeAndAfter } = new PokemonGoComponentDriver(); + beforeAndAfter(); + + beforeEach(() => { + given.onSubmitSpy(); + when.render(PokemonGoComponent); + }); + + it("Go button should be disabled", () => { + then(get.goButton()).shouldBeDisabled(); + }); + + it("when typing index Go button should be enabled", () => { + when.typePokemonIndex("33"); + then(get.goButton()).shouldBeEnabled(); + }); + + it("when typing index and submitting should call onSubmit", () => { + when.typePokemonIndex("33"); + when.clickGo(); + then(get.onSubmitSpy()).shouldHaveBeenCalledWith("33"); + }); + + it("should not update input value when typing non digits", () => { + when.typePokemonIndex("abcd-"); + then(get.pokemonIndexInputValue()).shouldEqual(""); + }); + + it("should clear input when clicking submit", () => { + when.typePokemonIndex("33"); + when.clickGo(); + then(get.pokemonIndexInputValue()).shouldEqual(""); + }); +}); diff --git a/examples/react/pokemon-catalog/src/components/pokemon-image/pokemon-image.component.tsx b/examples/react/pokemon-catalog/src/components/pokemon-image/pokemon-image.component.tsx index cec30366..5899a795 100644 --- a/examples/react/pokemon-catalog/src/components/pokemon-image/pokemon-image.component.tsx +++ b/examples/react/pokemon-catalog/src/components/pokemon-image/pokemon-image.component.tsx @@ -1,4 +1,4 @@ -import { SyntheticEvent, useState } from "react"; +import { SyntheticEvent, useEffect, useState } from "react"; import "./pokemon-image.scss"; export interface IProps { @@ -8,6 +8,7 @@ export interface IProps { export const PokemonImageComponent = (props: IProps) => { const { pokemonIndex } = props; const [showFallbackImage, setShowFallbackImage] = useState(false); + useEffect(() => setShowFallbackImage(false), [pokemonIndex]); const onImageError = (event: SyntheticEvent) => { setShowFallbackImage(true);