How should I be using playwright's toHaveScreenshot() within a cucumber test in a React Typescript project? - reactjs

I'm wanting to implement visual regression testing into a ReactJS app. I already have playwright setup called through cucumber for some other BDD UI tests and wanted to make use of the built in toHaveScreenShot method for visual regression. However, whenever I run the test it throws this error:
Error: toHaveScreenshot() must be called during the test
Here's the test script definition:
package.json excerpt
"test:e2e": "cucumber-js --require cucumber.conf.js --require features/step_definitions/**/*.js --format #cucumber/pretty-formatter",
Here's an example of the code:
cucumber.conf.js
const {
Before,
BeforeAll,
AfterAll,
After,
setDefaultTimeout,
} = require("#cucumber/cucumber");
const { chromium } = require("playwright");
// in milliseconds
setDefaultTimeout(60000);
// launch the browser
BeforeAll(async function () {
global.browser = await chromium.launch({
headless: false,
slowMo: 1000,
});
});
// close the browser
AfterAll(async function () {
await global.browser.close();
});
// Create a new browser context and page per scenario
Before(async function () {
global.context = await global.browser.newContext();
global.page = await global.context.newPage();
});
// Cleanup after each scenario
After(async function () {
await global.page.close();
await global.context.close();
});
homepage.feature
Feature: Homepage
A simple homepage
Scenario: Someone visiting the homepage
Given a new visitor to the site
When they load the homepage
Then they see the page
homepage.js
const { Given, When, Then } = require("#cucumber/cucumber");
const { expect } = require("#playwright/test");
Given("a new visitor to the site", function () {});
When("they load the homepage", async () => {
await page.goto("http://localhost:3000/");
});
Then("they see the page", async () => {
const locator = page.locator('img[alt="An image you expect to see"]');
await expect(locator).toBeVisible();
await expect(locator).toHaveScreenshot();
});
I think the error is complaining that I'm not writing my tests in the usual test() method, but I've not come across anything similar in searches and don't know how to give this context, assuming that is the problem, while using Cucumber.
Can anyone suggest a solution? I'm at a bit of a loss.

Related

Browser not Defined error in Jest-Image-Snapshot Testing in React

I want to implement https://github.com/americanexpress/jest-image-snapshot#-api in my React application and tried writing one of the test cases but gives me an error saying the browser is not defined when trying to run a test using the command "npm test".I am using a library called Jest-Image-snapshot by americanexpress
import { toMatchImageSnapshot } from 'jest-image-snapshot';
expect.extend({ toMatchImageSnapshot });
jest.setTimeout(10000);
it('renders correctly', async () => {
const page = await browser.newPage();
await page.goto('https://localhost:3000');
const image = await page.screenshot();
expect(image).toMatchImageSnapshot();
});

Why can't react testing library access elements with Selenium?

I have a selenium / jest project. I have installed react testing library and a few packages, but when I try to make valid assertions, I get an error. Code:
import { Vocal } from '../../Models/vocalModel';
import {screen} from '#testing-library/dom';
const vocal = new Vocal()
// Test Variables here
let validEmail = 'email#email.com'
let validPassword = 'password'
let invalidEmail = 'ThisEmailIsNotValid'
let invalidPassword = 'ThisPassWordIsNotValid'
describe("Login Test Suite", () => {
beforeAll(async ()=>{
await vocal.navigate();
});
afterAll( async ()=>{
await vocal.quit();
});
test('A user can login and logout', async () =>{
await vocal.userLogin(validEmail, validPassword);
await vocal.userLogout();
let getSignUpButtonText = await vocal.getText(vocal.signUpButtonLogin)
console.log(getSignUpButtonText)
expect(screen.getByText("Sign Up")).toBeVisible();
})
});
When I run this test, the browser runs and the test fails at the final assertion. I get the following error: "TestingLibraryElementError: Unable to find an element with the text: Sign Up. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.".
See photo:
Image of Error here
I've consoled 'getSignUpButtonText' which is defined as the text of that button on the page and it returns "Sign Up" so I know that text is on the page. Why can't screen.getByText('Sign Up') find it?
I have tried a few different packages but I cant seem to get away from this error.

Testing a component in Next.js with testing-library that relies on tRCP

I was experimenting with tRCP and diligently followed the setup for my Next.js project described in the official docs over here: https://trpc.io/docs/nextjs
However I noticed that a simple component that relies on tRPC such as this
export const Sample = () => {
const { data } = trpc.useQuery(['hello', { text: 'User' }]);
if (data === undefined) {
return <div>Loading...</div>;
}
return <div>{data.greeting}</div>;
};
cannot be properly tested since the following trivial test
describe('Sample', () => {
it('should render successfully', () => {
const { baseElement } = render(<Sample />);
expect(baseElement).toBeTruthy();
});
});
since there is no setup of provider such as the setup with the withTRCP HOC used for the application itself. As such the test fails claiming client (presumably the trcpClient, unlike the queryClient) is undefined.
I'd like to know how to setup the test correctly, in this case providing a correct client, as well as mocking the queries, since I don't have the respective server-side code running while invoking the tests.
Since you are getting undefined for the trpc client implementation, you can try spying on the query call.
import trpc from 'utils/trpc'; // This is the client implementation
describe('Sample', () => {
it('should render successfully', () => {
jest.spyOn(trpc, 'useQuery')
.mockReturnValue({ greeting: "Greeting" });
const { baseElement } = render(<Sample />);
expect(baseElement).toBeTruthy();
});
});
This is also possible with the mutations but you need to provide a mock implementation for the useMutation response for mutate property.

Cypress: Not able to stub with a basic example. What might i be missing?

For some reason, I am not able to stub this here. I have reduced my code to almost exactly this here. This should work according to the docs, but I'm wondering if I'm missing a finer detail of typescript / react hooks? That doesn't feel at all like the case but who knows. Thanks ahead of time if you're reading this and taking up your time. I appreciate what you do. Here's my example:
// connection.ts (the method to stub)
export const connectFn = async () => {
return 'i should not be here'
}
// ./reactHook.ts
import { connectFn } from './connection'
export const useMyHook = () => {
const handleConnect = async () => {
const result = await connectFn()
console.log(result)
// expected: 'i have been stubbed!'
// actual: 'i should not be here
}
return {
handleConnect
}
}
// ./App.ts
export const App = () => {
const { handleConnect } = useMyHook()
return <button onClick={handleConnect}>Connect</button>
}
// ./cypress/integration/connection.spec.ts
import * as myConnectModule from '../../connection'
describe('stub test', () => {
it('stubs the connectFn', () => {
cy.stub(myConnectModule, 'connectFn').resolves('i have been stubbed!')
cy.get('[data-testid=connect-btn]').click()
// assertions about the view here...
})
})
I thought I understood the cypress and Sinon docs pretty well. I have read that cypress needs an object to a stub from and not the named export directly - hence the * as an import. I have also tried every which way to export it as well. I used their example from the docs directly to no avail. I then thought it may be a typescript issue but it doesn't seem to be the case. I have reduced my actual code to pretty much this example here. I have even removed everything but the logs for testing and I'm still not getting it.
To stub successfully you need to stub (replace) the same instance.
In reactHook.ts
import { connectFn } from './connection'
if (window.Cypress) {
window.connectFn = connectFn
}
In the test
cy.window().then(win => {
cy.stub(win, 'connectFn').resolves('i have been stubbed!')
cy.get('[data-testid=connect-btn]').click()
...
}}
BTW useMyHook implies a React hook, if so you may need a cy.wait(0) to release the main JS thread and allow the hook to run.

Manual mocks with Jest -- I'm not understanding something

I'm learning jest, and trying to do a manual mock for an api, I'm missing something.
I'm mocking an api call to giphy. I'm seeing a lot of different syntaxes for the manual mocks, and unfortunately, they're not making much sense to me right now. I've been trying to code along with https://hackernoon.com/api-testing-with-jest-d1ab74005c0a and https://facebook.github.io/jest/docs/en/tutorial-async.html, but I'm stuck.
I have a component called GifListContainer that displays 3 gifs, there's search functionality, I just want a manual mock with fake data to learn.
I'm using create-react-app, I see a lot of people using isomorphic-fetch and other packages, but since jest is built in can't I do it without adding anything else?
I can't figure out how to manually write the mock, I feel I'm missing something simple. It's testing fine if I don't use the mock (using different testing syntax because I'm not testing the _ mock _ file). Thank you for your time.
The error I'm getting:
● should load gifs
TypeError: GifContainer.api is not a function
at Object.<anonymous>.it (src/Part_2/GifContainer.test.js:10:23)
✕ should load gifs (6ms)
GifListContainer.js
import {gifApi} from './api'
class GifListContainer extends Component {
state = {
gifs: []
};
componentDidMount() {
this.displayGifs('coding');
}
displayGifs = (query) => {
gifApi(query)
.then(res => res.json())
.then(json => {
let firstThreeGifs = json.data.slice(0, 3);
let urls = firstThreeGifs.map(
gif => gif.images.original.url.split("?")[0]
);
this.setState({
gifs: [...urls]
});
});
};
//after this there's a search function and the render and such.
api.js
const urlPartOne = "http://api.giphy.com/v1/gifs/search?q="
const urlPartTwo = "&api_key=UE0dCN2WofIwVF0RPbpHo0Lz0k9VhqdG"
const gifApi = (query) => {
return fetch(urlPartOne + query + urlPartTwo)
}
export {gifApi}
GifContainer.test.js
import React from 'react'
let mockFunction = jest.mock('./api.js');
import * as GifContainer from './GifContainer';
it('should load gifs', () => {
return GifContainer.displayGifs('sunshine')
.then(data => {
expect(data).toBeDefined()
expect(data.entity.data.type).toEqual('gif')
})
})
_ mocks _/api.js
I'm really just not getting how to write this.
const fs = require('fs')
const api = (query) => new Promise((resolve, reject) => {
fs.readFile(`./src/Part_2/__mockData__/query.json`, 'utf8', (err, data) => {
if (err) reject(err)
resolve({ entity: JSON.parse(data) })
})
})
export default api
and then mock data in a folder _ mockData _/sushine.json
/* http://api.giphy.com/v1/gifs/search?q=sunshine&api_key=UE0dCN2WofIwVF0RPbpHo0Lz0k9VhqdG */
{
"data": [
{
"type": "gif",
}
],
"meta": {
"status": 200,
"msg": "OK",
"response_id": "5b11716a33554c732e0ddf42"
}
}
Thank you!
I don't think so the problem is on the mock itself.
Actually, first of all you need to improve the way you are doing react unit testing.
Nowadays, there are tools like Enzyme(http://airbnb.io/enzyme/) which helps you a lot to test React components.
Have you check the Testing React Apps section for Jest? Specially the DOM Testing part? Take a look here: https://facebook.github.io/jest/docs/en/tutorial-react.html#dom-testing
Back to your problem, I think it's because you are exporting the fn as default in the mock file but haven't done that on the api file. Try to put both equals and let me know!

Resources