Jangan gunakan perlengkapan di Cypress dan pengujian unit - gunakan fungsi pabrik

Untuk calon siswa di kursus "JavaScript QA Engineer" dan semua orang yang tertarik dengan topik otomatisasi pengujian, kami menyiapkan terjemahan untuk artikel yang bermanfaat.



Kami juga mengundang Anda untuk mengikuti webinar terbuka dengan topik "Apa yang perlu diketahui penguji tentang JS" . Dalam pelajaran ini, peserta bersama seorang ahli akan mempertimbangkan fitur-fitur JS yang perlu diperhatikan saat menulis tes.










Tes unit sangat bagus ... ketika mereka bekerja dengan andal! Faktanya, ada pepatah lama yang mengatakan bahwa "ujian yang buruk lebih buruk daripada tidak ada ujian sama sekali." Saya dapat mengonfirmasi bahwa berminggu-minggu yang dihabiskan untuk mengejar tes "negatif palsu" yang tidak disengaja tidaklah efektif. Sebaliknya, kali ini dapat digunakan untuk menulis kode kerja untuk membantu pengguna.





: .





, , , .





,









  1. ( )









.





?

— , . . , « », "Gang Of Four's Design Pattern" . .





, , .





:





interface ISomeObj {
  percentage: string;
}

export const makeSomeObj = () => {
  return {
    percentage: Math.random()
  };
}
      
      



, , .





, , .





,

. , - . JSON-. Cypress ( ), JSON . , . JSON .





, . , , , .





// This file is "src/pages/newYorkInfo.tsx"
import * as React from 'react';

interface IUser {
    state: string;
    address: string;
    isAdmin: boolean;
    deleted: boolean | undefined;
}

export const NewYorkUserPage: React.FunctionComponent<{ user: IUser }> = props => {
    if (props.user.state === 'NY' && !props.user.deleted) {
        const welcomeMessage = `Welcome`;
        return <h1 id="ny-dashboard">{welcomeMessage}</h1>;
    } else {
        return <div>ACCESS DENIED</div>;
    }
};
      
      



, JSON .





// fixtures/user.json
{
    state: 'NY',
    isAdmin: true,
    address: '55 Main St',
}
      
      



. , - psuedo- Cypress, , , .





// When the UI calls the user endpoint, return the JSON as the mocked return value
cy.route('GET', '/user/**', 'fixture:user.json');
cy.visit('/dashboard');
cy.get('#ny-dashboard').should('exist')
      
      



, , . ?





— , JSON-

JSON- ? , , (). , JSON-. 52 JSON-, . , , 104 . !





. , Product Owner : « , ».





, name



.





// This file is "src/pages/newYorkInfo.tsx"
import * as React from 'react';

interface IUser {
    name: string;
    state: string;
    address: string;
    isAdmin: boolean;
    deleted: boolean | undefined;
}

export const NewYorkUserPage: React.FunctionComponent<{ user: IUser }> = props => {
    if (props.user.state === 'NY' && !props.user.deleted) {
        const welcomeMessage = `Welcome ${props.user.name.toLowerCase()}!`;
        return <h1 id="ny-dashboard">{welcomeMessage}</h1>;
    } else {
        return <div>ACCESS DENIED</div>;
    }
};
      
      



, , JSON . JSON name



, :





Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
      
      



name 52 JSON . Typescript.





: TypeScript

JSON .ts , Typescript :





// this file is "testData/users"
import {IUser} from 'src/pages/newYorkInfo';

// Property 'name' is missing in type '{ state: string; isAdmin: true; address: string; deleted: false; }' but required in type 'IUser'.ts(2741)
export const generalUser: IUser = {
    state: 'NY',
    isAdmin: true,
    address: '55 Main St',
    deleted: false,
};
      
      



, .





import { generalUser } from 'testData/users';

// When the UI calls the user endpoint, return the JSON as the mocked return value
cy.route('GET', '/user/**', generalUser);
cy.visit('/dashboard');
cy.get('#ny-dashboard').should('exist')
      
      



Typescript! , name: 'Bob Smith'



GeneralUser:



, , , !





, . , .





, , , -. , , , , . deleted: false



generalUser



.





! , . .





( ) , . , ( ) deletedUser



, 1 . - — 5000 .





, .





// this file is "testData/users"
import {IUser} from 'src/pages/newYorkInfo';

export const nonAdminUser: IUser = {
    name: 'Bob',
    state: 'NY',
    isAdmin: false,
    address: '55 Main St',
    deleted: false,
};

export const adminUser: IUser = {
    name: 'Bob',
    state: 'NY',
    isAdmin: true,
    address: '55 Main St',
    deleted: false,
};

export const deletedAdminUser: IUser = {
    name: 'Bob',
    state: 'NY',
    isAdmin: true,
    address: '55 Main St',
    deleted: true,
};

export const deletedNonAdmin: IUser = {
    name: 'Bob',
    state: 'NY',
    isAdmin: false,
    address: '55 Main St',
    deleted: true,
};

// and on and on and on again...
      
      



.





:  

? !





// src/factories/user
import faker from 'faker';
import {IUser} from 'src/pages/newYorkInfo';

export const makeFakeUser = (): IUser => {
    return {
        name: faker.name.firstName() + ' ' + faker.name.lastName(),
        state: faker.address.stateAbbr(),
        isAdmin: faker.random.boolean(),
        address: faker.address.streetAddress(),
        deleted: faker.random.boolean(),
    }
}
      
      



makeFakeUser()



, .





, , , , . IUser, .





. , - . , .





import { makeFakeUser } from 'src/factories/user';
import {IUser} from 'src/pages/newYorkInfo';

// Arrange
const randomUser = makeFakeUser();
const deletedUser: IUser = { ...randomUser, ...{
  deleted: true
};
cy.route('GET', '/user/**', deletedUser);

// Act
cy.visit('/dashboard');

// Assert
cy.find('ACCESS DENIED').should('exist')
      
      



, , . , , , API , "Access Denied"



.





, .





: mergePartially

spread



, . , , :





interface IUser {
    userName: string;
    preferences: {
        lastUpdated?: Date;
        favoriteColor?: string;
        backupContact?: string;
        mailingAddress: {
            street: string;
            city: string;
            state: string;
            zipCode: string;
        }
     }
}
      
      



, .





, , DRY. , , , "Main Street".





const userOnMainSt = makeFakeUser({
    preferences: {
        mailingAddress: {
            street: 'Main Street'
        }
    }
});
      
      



, , , 7 . - . .





makeFakeUser







, mergePartially ( : mergePartially



).





const makeFakeUser = (override?: NestedPartial<IDeepObj>): IDeepObj => {
        const seed: IDeepObj = {
          userName: 'Bob Smith',
          preferences: {
            mailingAddress: {
              street: faker.address.streetAddress(),
              city: faker.address.city(),
              state: faker.address.stateAbbr(),
              zipCode: faker.address.zipCode(),
            },
          },
        };
        return mergePartially.deep(seed, override);
      };
      
      



, , .





, .






«JavaScript QA Engineer».









« JS ».












All Articles