Next js-ის სატის გატესტვა cypress-ით

პატარა განსხვავებების აღწერა next js-ის და რეაქტის გატესტვის შორის

Next js+Cypress-ის პრობლემა

ფრონტში ტესტების წერის მთავარი მიზანი ის არის რომ ფრონტენდი გავატესტოთ და არა ბექენდი ან რაიმე სხვა third party პროვაიდერი, ჩვენ იზოლირებულად უნდა გავატესტოთ ჩვენი ფრონტენდი და არცერთი რექუესტი არ უნდა გავედეს ნამდვილ სამყარუში, ჩვენ არ გვინდა რომ ჩვენი ტესტები ბექის პრობლემის გამო ~ჩაფლავდეს~ წარმუატებელი აღმოჩნდეს, ამის მიღწევა React-ის გატესტვის დროს საკმაოდ მარტივი იყო cy.intercept-ის საშუალებით, 🤔მაგრამ ნექტის პროექტში ეს არ არის საკმაირისი, 😢ამის მიზეზის გასაგებად ჯერ უნდა დავფიქრდეთ რას შვება cypress-ი:

cypress-ი ხსნის ჩვენ აპლიკაციას ბრაუზერში რომელსაც ის აკონტროლებს და რისი საშუალებითაც შეუძლია გვერდებზე შესვლა და ნამდვილი მომხმარებელივით მოქცევა, კაი ეს თუ გასაგებია დავფიქრდეთ რას შვება Next js-ი: next-ი სერვერზე აწყობს ჩვენ რექტის კოდს და მომხმარებელს წინასწარ გენერირებულ გვერდს უგზავნის, ასე ჩვენ ნექტში შეგვიძლია სერვერის მხარესაც კოდის გაშვება, მაგალითად: getServerSideProps-ის ფუნქცია სადაც api-იდან ინფოს წამოღება შეგვიძლია,

სწორედ getServerSideProps-ი და სხვა ამ სახის ფუნქციები არის პრობლემა cypress-ით გატესტვის დროს, იმის გამო რომ cypress-ს მარტო ბრაუზერის კონტროლი შეუძლია და სერვერზე არაფერი არ შეუძლია, ჩვენ არ შეგვიძლია getServerSideProps-ში გაგზავნილი api call-ის შეწყვეტა და ინფორმაციის ხელით მიწოდება... მაშინ როგორ შეგვიძლია ამის გადაჭრდა? cypress-ს თუ არ აქვს ამის შესაძლებლობა მოდი სხვა tool-ი შემოვიტანოთ თამაშში nock,

არ იდარდო ამისთვის ფიქრი და წვალება ჩვენთვის უკვე გაკეთებული იყო >:)

Nock-ის cpyress-სთან გამოყენება

საბედნიეროთ ჩვენ არ მოგვიწევს nock-ის ხელით კონფიგურაცია და გამზადებული package-ი გვაქვს, სამწუხაროთ package-ი ჯერ დეველოპმენტის პროცესშია და მაინც მოგვიწევს რამოდენიმე რაღაცის გაკეთება, მოდი დავაინსტალიროთ ეს package-ი:

npm install --dev https://github.com/cypress-io/cypress-mock-ssr#master

და ასევე express-ი დაგვჭირდება

npm install --save-dev express

ალბათ როგორც მიხვდით ეს package-ი სერვერზე მანიპულაციას ჩაატარებს მაგრამ ნექტი ეს ნექტში როგორ ვქნათ?

მარტვია: nextjs custom servers თუ დოკუმენტაციას გაადავლე თვალი (რასაც გირჩევდი) შეამჩნევდი რომ ამას თუ გამოვიყენებთ სტატიკური გენერირებას დავკარგავთ 😢, რაც იმას ნიშნავს რომ ჩვენ საიტი შენელდება, რის გამოც ამ custom server-ს მარტო ტესტებისთვის გამოვიყენებთ, მოდი შევქმნათ ის

cypress-ის საქაღალდეში შევქმნათ ფაილი სახელით nextTestServer.ts (სახელი თქვენზეა რათქმაუნდა) და შიგნით შემდეგი კოდი ჩავწეროთ:

const express = require('express');
const next = require('next');
const { cypressMockMiddleware } = require('@cypress/mock-ssr');

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  const server = express();


  server.use(cypressMockMiddleware());

  server.use((req, res) => {
    return handle(req, res);
  });

  server.listen(port, (err) => {
    if (err) throw err;
    console.log(`> Ready on http://localhost:${port}`);
  });
});

და მოდი ჩვენი package.json-ის შევცვალოთ ცოტა

"nextTestServer": "node cypress/testServer.ts"

ეხლ npm run nextTestServer -ს თუ გავუშვებთ დავინახავთ რომ ჩვენი სერვერი წარმატებით ჩაიერთო და რომ შევიდეთ ყველაფერი იგივე იქნება 🤯, უფრო ნელი ოღონდ :/, კაი მოდი mock-ssr-ის package-ს დავუბრუნდეთ:

cypress/support/e2e.ts-ის ფაილში უნდა დავაპატოთ ეს იმპორტი:

import '@cypress/mock-ssr';

ამ package-ს TS-ისთვის support-ი არ აქვს და თუ მას იყენებ პროექტში ასე შეცვლაე შენი გლობალური Chainable interface-ი

declare global {
  namespace Cypress {
    interface Chainable {
      mockUserRelationsContextRequests(): void;
      clearSSRMocks(): void;
      mockSSR({}: {
        hostname: string;
        method: string;
        path: string;
        statusCode: 200 | 404 | 500 | 403;
        body: {
          [key: string]: any;
        };
      }): void;
      // rest of the configuration
    }
  }
}

ასევე უნდა შევიდეთ cypress/support/commands.ts-ში და შემდეგი ბრძანებები ჩავამტოთ:

after(() => {
  cy.clearSSRMocks();
});

Cypress.Commands.add('mockSSR', (payload) => {
  cy.request('POST', '/__cypress_server_mock', payload);
});

Cypress.Commands.add('clearSSRMocks', () => {
  cy.request('/__cypress_clear_mocks');
});

mockSSR და clearSSRMocks-ი ბრძანებები mock ssr ის package-ის შემქმენელბის მიერ გაკეთებულ middleware-ს უგზავნის ინფორმაციას, სადაც უკვე nock-ის საშუალებით ჩვენი api request-ი შეწყდება და ჩვენ მიერ გაწერილი ინფო დარდუნდება, და after-ი კი უბრალოდ წმინდეავს ყველა mocks-ს ტესტის დასრულების შემდეგ, არ გვინდა რომ ისინი დაგვიგროვდეს

mock-ssr-ის გამოყენება

მისი გამოყენება საკმაოდ მარტივია, სანამ გვერდს ვეწვევით უბრალოდ უნდა გავუშვათ ასეთი სახის ბრძანებები:

  cy.mockSSR({
    hostname: Cypress.env('apiHostname'),
    method: 'GET',
    path: '/api/skills',
    statusCode: 200,
    body: skills,
  });

და კი ბრძანებები, ჩვენ შეგვიძლია ერთი route-ის ვიზიტისას რამოდენიმე რექუესტი გავაჩეროთ >:)

დაა ვსო ეს არის გატესტვასთან აღარეფი ცვილილება არ იქნება, მარა coverage-ის გაგებასთან იქნება >:)

Test coverage-ი Istanbul-ის საშუალებით

თუ გაინტერესებს აქ რაღა შეიცვლა... ბევრი არაფერი, იგივე რომ ქნა რაც react-ის პროექტში იმუშავებს, მაგრამ ერთი ძალიან დიდი პრობლემა გვაქ მაგასთან რაც არის: babel-ი istanbul-ის გამოყენება მარტო bable-ის მეშვეობით შეგვიძლია, რაც რექტში არ არის პრობლემა რადგანაც ის ისედაც babel-ს იყენებს მაგრამ next-ი სხვა კომპაილერს სახელად SWC-ის იყენებს, და SWC-ი არის bable-ზე 20-ჯერ სწრაფია ნუ თუ SWC-ის საიტს დავუჯერბთ, 20-ჯერ-ზე არ ვიცი მაგრამ ბევრად სწრაფი არის და ამის დათმობა ჩვენ არ გვაწყობს დეელოპმენტი უფრო ნელი იქნება, სერვერზე ატანა build-ის პროცესის შენელების გამო ნელი იქნება, და არც ერთი არ გვაწყობს, მარა ეს როგორ მოვაგვაროთ? სამწუხაროთ კარგი გზა ამის არ არსეობს SWC-ში istanbul-ის ჩამატეა არ შეგვიძლია, მოდი არც ისე სუფთა გზას მივმართოთ 🧐, და ჩვენი .gitignore-ი შევცვალოთ პირველი:

.babelrc-ი ჩავამატოთ შიგნით,

მერე package.json-ი უნდა შევცვალოთ:

დავამატოთ ეს ბრძანება რომელიც .babelrc-ის შექმნის:

"instrumentAppForTest": "rm .babelrc -f && echo '{ \"presets\": [\"next/babel\"], \"plugins\": [\"istanbul\"] }' >> .babelrc",

ასე გადავასწოროთ ჩვენი dev-ი და build-ის ბრძანებები:

"dev": "rm .babelrc -f &&  next dev",
"build": "rm .babelrc -f && next build",

და ასევე შევცვალოთ custom სერვერის გაშვების ბრძანებაც ასე:

"nextTestServer": "node cypress/testServer.ts -r @cypress/instrument-cra start"

დაა ეს არის, სანამ ტესტებს დავიწყებთ გავუშვებთ npm run instrumentAppForTest და build/dev-ის გაშვების შემდგ ის წაიშლება და SWC-ის გამოიყენებს ნექტი,

we get best of both worlds speed of SWC and coverage of babel 🙌

Last updated