برنامه نویسی

کارگاه سرو قسمت 11: گزارش – قاس، اقدامات Github

یک آشفتگی

Qase یک ابزار مدیریت تست است که برای مستندسازی تست، اجرای تست، گزارش گیری و غیره استفاده می شود. در این آموزش، نحوه اتصال تست خود را در Cypress و فشار دادن نتایج به Qase یاد خواهید گرفت. این به داشتن یک گزارش برای آزمایش دستی و خودکار کمک می کند.

مراحل:

  • به وب سایت قاس بروید و حساب کاربری ایجاد کنید: Qase
  • پس از انجام این کار، یک پروژه جدید به نام کارگاه Cypress – فروشگاه کتاب ایجاد کنید

توضیحات تصویر

  • در داخل پروژه یک مجموعه آزمایشی جدید ایجاد کنید و به عنوان مثال آن را وب نامید.
  • در داخل مجموعه وب، همه موارد آزمایشی را که برای برنامه فروشگاه کتاب خودکار کرده‌ایم ایجاد و مستند کنید. آنها را با تمام جزئیات و مراحل پر کنید. یک مورد آزمایشی اضافی به عنوان مثال برای ثبت نام ایجاد کنید، که بخشی از مجموعه اتوماسیون ما نیست، ما می خواهیم آن را به صورت دستی اجرا کنیم، اما هنوز باید در اینجا مستند شود.

توضیحات تصویر

توضیحات تصویر

  • یک طرح آزمایشی جدید ایجاد کنید و به عنوان مثال آن را رگرسیون وب نامید. تمام موارد آزمایشی ما را در آنجا قرار دهید.

توضیحات تصویر

  • به اجرای آزمایشی بروید و یک اجرای آزمایشی جدید ایجاد کنید که شامل تمام موارد آزمایشی از طرح آزمایشی است. اجرای آزمایشی را شروع کنید.

توضیحات تصویر

  • به تنظیمات پروژه ← تنظیمات بروید و این دو نقطه را بررسی کنید تا امکان فشار انبوه نتایج سرو فراهم شود

توضیحات تصویر

  • به صفحه api tokens بروید و یک توکن جدید ایجاد کنید. ارزش رمز را در جایی ذخیره کنید که بعداً به آن نیاز خواهیم داشت.

توضیحات تصویر

توضیحات تصویر

  • به پروژه cypress خود بروید و در ترمینال این 3 دستور را برای نصب وابستگی برای Qase اجرا کنید:

npm install cypress-qase-reporter

npm install dotenv

npm install prompt

  • در زیر پوشه اصلی پروژه، اسکریپت های پوشه جدید و فایل جدید ایجاد کنید cypress-with-qase.js
  • برای مدیریت اجرای آزمایشی با حروف بزرگ، کد زیر را در داخل آن بنویسید (در هر فرمان اجرای، مقادیر خاصی از پروژه و اجرا را درخواست می‌کند، و همچنین می‌پرسد کدام مجموعه اتوماسیون را می‌خواهید اجرا کنید. ما همچنین پیکربندی اولیه Cypress را ارائه می‌دهیم)
require('dotenv').config();
const prompt = require('prompt');
const cypress = require('cypress');

prompt.start();
prompt.get(
    [
        {
            name: 'PROJECT_ID',
            description: 'Provide Qase PROJECT_ID',
            type: 'string',
            required: true,
        },
        {
            name: 'RUN_ID',
            description: 'Provide RUN_ID for the Qase test run',
            type: 'number',
            required: true,
        },
        {
            name: 'SUITE',
            description: 'Provide SUITE folder path for the Qase test run',
            type: 'string',
            required: true,
        },
    ],
    function (err, result) {
        cypress.run({
            spec: `cypress/e2e/${result.SUITE}/*.cy.js`,
            browser: 'chrome',
            reporter: 'cypress-qase-reporter',
            headed: true,
            reporterOptions: {
                apiToken: process.env.QASE_API_KEY,
                projectCode: result.PROJECT_ID,
                runId: result.RUN_ID,
                logging: true,
            },
        });
    }
);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • به فایل package.json بروید و دستور جدیدی برای اجرای Cypress با Qase اضافه کنید (خط 13):
{
  "name": "cypress-workshop",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "cypress-cli-prod": "cypress open --env prod=1",
    "cypress-headed-prod": "cypress run --headed -b chrome --env prod=1",
    "cypress-headless-prod": "cypress run --headless -b chrome --env prod=1",
    "cypress-cli-staging": "cypress open",
    "cypress-headed-staging": "cypress run --headed -b chrome",
    "cypress-headless-staging": "cypress run --headless -b chrome",
    "cypress:run:qase": "QASE_REPORT=1 node scripts/cypress-with-qase.js",
    "eslint": "eslint cypress",
    "eslint-fix": "eslint cypress --fix"
  },
  "author": "",
  "license": "ISC",
  "husky": {
    "hooks": {
      "pre-commit": "npm run eslint-fix"
    }
  },
  "devDependencies": {
    "cypress": "^10.0.0",
    "eslint": "^8.16.0",
    "eslint-config-airbnb": "^19.0.4",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-chai-friendly": "^0.7.2",
    "eslint-plugin-cypress": "^2.12.1",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-jsx-a11y": "^6.5.1",
    "eslint-plugin-prettier": "^4.0.0",
    "eslint-plugin-react": "^7.30.0",
    "husky": "^8.0.1",
    "prettier": "^2.6.2"
  },
  "dependencies": {
    "cypress-file-upload": "^5.0.8",
    "cypress-qase-reporter": "^1.4.2-alpha.2",
    "dotenv": "^16.0.1",
    "prompt": "^1.3.0"
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • اکنون به برنامه Qase برگردید و شناسه های هر مورد آزمایشی را بیابید. این یک عدد در کنار ID پروژه است (به عنوان مثال، در اینجا CWBS یک ID پروژه است و 1 ID case و غیره):

توضیحات تصویر

  • به پروژه اتوماسیون خود برگردید و کلید API را از Qase که قبلاً دریافت کرده بودیم صادر کنید. به این صورت است که باید آن را بنویسید و در ترمینال اجرا کنید، اما کلید شما متفاوت است، کلید خود را از مرحله 8 در اینجا جای‌گذاری کنید:

export QASE_API_KEY=46b7d640b6841da28aea575cb6084141661976bcq

  1. هر مورد آزمایشی را ویرایش کنید تا شناسه‌های شما را از Qase درج کند، ما در اینجا اسناد را با اتوماسیون مطابقت می‌دهیم:

addBookToProfile.cy.js:

/// <reference types="Cypress" />

import { qase } from 'cypress-qase-reporter/dist/mocha';
import { bookActions } from '../../support/bookstore_page_objects/book_store';
import { navigateTo } from '../../support/bookstore_page_objects/navigation';

describe('Collections: Add Book To Collection', () => {
  // Perform login
  beforeEach('Perform login', () => {
    cy.createUser();
    cy.generateToken();
  });

  // Delete user
  afterEach('Delete user', () => {
    cy.deleteUser();
  });

  qase(
    1,
    it('Check adding book to profile collection', () => {
      // Navigate to book store
      navigateTo.bookStore();
      // Load books fixture
      cy.fixture('books').then((books) => {
        // Add first books to collection
        bookActions.addBookToCollection(books.collection1.Git);
        // Handle alert and verify alert message
        cy.verifyWindowAlertText(`Book added to your collection.`);
        // Navigate to user profile and verify that book is in collection table
        navigateTo.profile();
        cy.get('.rt-tbody').find('.rt-tr-group').first().should('contain', books.collection1.Git);
      });
    })
  );
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

checkBookInfo.cy.js:

/// <reference types="Cypress" />

import { qase } from 'cypress-qase-reporter/dist/mocha';
import { bookActions } from '../../support/bookstore_page_objects/book_store';
import { profileActions } from '../../support/bookstore_page_objects/profile';
import { navigateTo } from '../../support/bookstore_page_objects/navigation';

describe('Collections: Check Book Info', () => {
  // Perform login
  beforeEach('Perform login', () => {
    cy.createUser();
    cy.generateToken();
  });

  // Add book to book collection
  beforeEach('Add book to profile collection', () => {
    navigateTo.bookStore();
    cy.fixture('books').then((books) => {
      bookActions.addBookToCollection(books.collection1.DesignPatternsJS);
      cy.verifyWindowAlertText(`Book added to your collection.`);
    });
  });

  // Delete user
  afterEach('Delete user', () => {
    cy.deleteUser();
  });

  qase(
    2,
    it('Check book info from profile table', () => {
      // Navigate to user profile
      navigateTo.profile();
      // Load books fixture
      cy.fixture('books').then((books) => {
        // Click on book in collection to open book info
        profileActions.checkBookData(books.collection1.DesignPatternsJS);
      });
      // Define book info elements
      const bookDataElements = [
        '#ISBN-label',
        '#title-label',
        '#subtitle-label',
        '#author-label',
        '#publisher-label',
        '#pages-label',
        '#description-label',
        '#website-label',
      ];
      // Check book info elements
      cy.elementVisible(bookDataElements);
      // Define data about the book
      const bookData = [
        '9781449331818',
        'Learning JavaScript Design Patterns',
        `A JavaScript and jQuery Developer's Guide`,
        'Addy Osmani',
        `O'Reilly Media`,
        '254',
      ];
      // Check data about the book
      cy.textExists(bookData);
    })
  );
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

deleteBookFromProfile.cy.js:

/// <reference types="Cypress" />

import { qase } from 'cypress-qase-reporter/dist/mocha';
import { bookActions } from '../../support/bookstore_page_objects/book_store';
import { profileActions } from '../../support/bookstore_page_objects/profile';
import { navigateTo } from '../../support/bookstore_page_objects/navigation';

describe('Collections: Delete Book From Collection', () => {
  // Perform login
  beforeEach('Perform login', () => {
    cy.createUser();
    cy.generateToken();
  });

  // Add book to collection
  beforeEach('Add book to profile collection', () => {
    navigateTo.bookStore();
    cy.fixture('books').then((books) => {
      bookActions.addBookToCollection(books.collection1.SpeakingJS);
      cy.verifyWindowAlertText(`Book added to your collection.`);
    });
  });

  // Delete user
  afterEach('Delete user', () => {
    cy.deleteUser();
  });

  qase(
    3,
    it('Check deleting book from profile collection - confirm deletion', () => {
      cy.fixture('books').then((books) => {
        // Navigate to user profile
        navigateTo.profile();
        // Check if book is in the collection table
        cy.get('.rt-tbody')
          .find('.rt-tr-group')
          .first()
          .should('contain', books.collection1.SpeakingJS);
        // Delete book from table - confirm deletion
        profileActions.deleteBookFromTable(books.collection1.SpeakingJS, 'ok');
        // Handle delete alert and verify message
        cy.verifyWindowAlertText(`Book deleted.`);
        // Verify that book is no longer in collection table and that table is empty
        cy.get('.rt-tbody').should('not.contain', books.collection1.SpeakingJS);
        cy.get('.rt-noData').should('contain', 'No rows found').should('be.visible');
      });
    })
  );

  qase(
    6,
    it('Check deleting book from profile collection - decline deletion', () => {
      cy.fixture('books').then((books) => {
        // Navigate to user profile
        navigateTo.profile();
        // Check if book is in the collection table
        cy.get('.rt-tbody')
          .find('.rt-tr-group')
          .first()
          .should('contain', books.collection1.SpeakingJS);
        // Cancel book deletion
        profileActions.deleteBookFromTable(books.collection1.SpeakingJS, 'cancel');
        // Verify that book is still in the table
        cy.get('.rt-tbody').should('contain', books.collection1.SpeakingJS);
      });
    })
  );
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

login.cy.js:

/// <reference types="Cypress" />

import { qase } from 'cypress-qase-reporter/dist/mocha';
import { auth } from '../../support/bookstore_page_objects/auth';
import { navigateTo } from '../../support/bookstore_page_objects/navigation';

describe('Auth: Login user', () => {
  // Navigate to login page
  beforeEach('Navigate to Login page', () => {
    navigateTo.login();
  });
  qase(
    7,
    it('Check valid user credentials', () => {
      // Load users fixture
      cy.fixture('users').then((users) => {
        // Perform login
        auth.login(users.user2.username, users.user2.password);
      });
      // Verify that user is redirected to profile page (user is logged in)
      cy.url().should('contain', Cypress.env('profile'));
    })
  );

  qase(
    8,
    it('Check invalid user credentials', () => {
      // Perform login
      auth.login('invalid345', 'invalid345');
      // Verify that user is still on login page (user is not logged in)
      cy.url().should('contain', Cypress.env('login'));
      // Verify that error message is displayed
      cy.get('#output').should('contain', 'Invalid username or password!');
    })
  );

  qase(
    9,
    it('Check login with invalid username and valid password', () => {
      // Load users fixture
      cy.fixture('users').then((users) => {
        // Perform login
        auth.login('invalid345', users.user2.password);
      });
      // Verify that user is still on login page (user is not logged in)
      cy.url().should('contain', Cypress.env('login'));
      // Verify that error message is displayed
      cy.get('#output').should('contain', 'Invalid username or password!');
    })
  );

  qase(
    10,
    it('Check login with valid username and invalid password', () => {
      // Load users fixture
      cy.fixture('users').then((users) => {
        // Perform login
        auth.login(users.user2.username, 'invalid345');
      });
      // Verify that user is still on login page (user is not logged in)
      cy.url().should('contain', Cypress.env('login'));
      // Verify that error message is displayed
      cy.get('#output').should('contain', 'Invalid username or password!');
    })
  );
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

logout.cy.js:

/// <reference types="Cypress" />

import { qase } from 'cypress-qase-reporter/dist/mocha';
import { auth } from '../../support/bookstore_page_objects/auth';
import { navigateTo } from '../../support/bookstore_page_objects/navigation';

describe('Auth: Log out user', () => {
  // Perform login
  beforeEach('Perform login', () => {
    cy.createUser();
    cy.generateToken();
  });

  // Delete user
  afterEach('Delete user', () => {
    cy.deleteUser();
  });

  qase(
    11,
    it('Check logging out user', () => {
      // Navigate to user profile
      navigateTo.profile();
      // Perform log out
      auth.logout();
      // Assert that user is on login page
      cy.url().should('contain', Cypress.env('login'));
    })
  );
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

searchBookstore.cy.js:

/// <reference types="Cypress" />

import { qase } from 'cypress-qase-reporter/dist/mocha';
import { bookActions } from '../../support/bookstore_page_objects/book_store';
import { navigateTo } from '../../support/bookstore_page_objects/navigation';

describe('Bookstore: Search For Book', () => {
  // Perform login
  beforeEach('Perform login', () => {
    cy.createUser();
    cy.generateToken();
  });

  // Delete user
  afterEach('Delete user', () => {
    cy.deleteUser();
  });

  qase(
    12,
    it('Check searching for existing book in book store', () => {
      // Navigate to bookstore
      navigateTo.bookStore();
      // Load books fixture
      cy.fixture('books').then((books) => {
        // Perform book search
        bookActions.searchCollection(books.collection1.DesignPatternsJS);
        // Verify that there is a book in filtered table (in search result)
        cy.get('.rt-tbody')
          .find('.rt-tr-group')
          .first()
          .should('contain', books.collection1.DesignPatternsJS);
      });
    })
  );

  qase(
    13,
    it('Check searching for non-existing book in book store', () => {
      // Define invalid book name
      const invalid_book_name = 'Game of Thrones';
      // Navigate to bookstore
      navigateTo.bookStore();
      // Perform book search
      bookActions.searchCollection(invalid_book_name);
      // Assert that there are no search results (no book in the table and table is empty)
      cy.get('.rt-tbody').should('not.contain', invalid_book_name);
      cy.get('.rt-noData').should('contain', 'No rows found').should('be.visible');
    })
  );
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • در نهایت بیایید تست ها را اجرا کنیم. در ترمینال خود دستور execute را بنویسید

npm run cypress:run:qase

و به سوالات پاسخ دهید، شناسه پروژه، شناسه اجرا و مجموعه ای را که می خواهید اجرا کنید، در این مورد مجموعه کتابفروشی ارائه دهید.

وقتی به صفحه اجرای آزمایشی خود می روید، فقط در URL به عنوان آخرین شماره می توانید شناسه اجرا را پیدا کنید:

توضیحات تصویر

توضیحات تصویر

  • پس از اتمام اجرای آزمایشی، می‌توانید نتایج را در ترمینال و همچنین در برنامه Qase ببینید، فقط صفحه اجرای آزمایشی را در Qase بازخوانی کنید.

توضیحات تصویر

توضیحات تصویر

همانطور که می بینید تمام نتایج آزمایشات از Cypress در Qase بارگذاری می شود. ما فقط یک تست دستی برای اجرا داریم و می توانید آن را به صورت دستی در خود قاس اجرا کنید. که ما اجرای تست خودکار و دستی را با هم ترکیب کردیم.

توضیحات تصویر

توضیحات تصویر

اقدامات Github

GitHub Actions یک پلتفرم یکپارچه سازی و تحویل مداوم (CI/CD) است که به شما امکان می دهد خط لوله ساخت، آزمایش و استقرار خود را خودکار کنید. می‌توانید گردش‌های کاری ایجاد کنید که هر درخواست کششی را در مخزن شما ایجاد و آزمایش کند، یا درخواست‌های کشش ادغام‌شده را در تولید مستقر کنید.

GitHub Actions فراتر از DevOps است و به شما اجازه می دهد تا زمانی که رویدادهای دیگری در مخزن شما اتفاق می افتد، گردش کار را اجرا کنید. به عنوان مثال، می‌توانید یک گردش کار را اجرا کنید تا هر زمان که شخصی مشکل جدیدی در مخزن شما ایجاد کرد، برچسب‌های مناسب را به‌طور خودکار اضافه کنید.

GitHub ماشین‌های مجازی لینوکس، ویندوز و macOS را برای اجرای گردش‌های کاری شما فراهم می‌کند، یا می‌توانید در مرکز داده یا زیرساخت ابری خود میزبان خود میزبانی کنید.

ℹ️ درباره Github Actions بیشتر بدانید: Github Actions

ℹ️ Github Actions + Cypress: GA و Cypress

شما می توانید خطوط لوله CI/CD خود را با توجه به نیازهای پروژه خود سفارشی کنید. در این نسخه ی نمایشی یک نمونه از اقدامات github ایجاد می کنیم که به ما امکان می دهد چند عمل ساده را انجام دهیم:

  • برنامه cron job را برای اجرای تست سرو در ساعت 10 صبح UTC هر یکشنبه برنامه ریزی کنید
  • تست های سرو را در هر فشار به شاخه اصلی اجرا کنید

کار اجرای آزمایشی سرو شامل موارد زیر است:

  • تعریف ظرف و ماشینی که آزمایش‌ها در آن اجرا می‌شوند
  • نصب وابستگی ها
  • اجرای تمام تست‌های ما در حالت پیش‌فرض بدون سر در Chrom

بنابراین، چگونه این را بنویسیم؟

  • یک پوشه جدید .github در فهرست اصلی ایجاد کنید.
  • یک پوشه جدید در جریان کار، تحت github. ایجاد کنید
  • یک فایل جدید main.yml ایجاد کنید

محتوای زیر را در داخل بنویسید (بهتر است کپی پیست شود زیرا این فایل به فاصله ها و غیره حساس است):

name: Cypress Tests

on:
  schedule:
  #schedule at 10:00 on Sunday
  - cron: '0 10 * * sun'
  push:
    branches:
      - main
jobs:
  cypress-run:
    runs-on: ubuntu-latest
    container: cypress/browsers:node12.18.3-chrome87-ff82
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Install dependencies
        run: npm install    

      - name: 'Run all tests'
        uses: cypress-io/github-action@v4
        with:
          # we have already installed all dependencies above
          install: false
          wait-on: 'https://demoqa.com'
          wait-on-timeout: 120
          browser: chrome
          spec: cypress/e2e/**/*
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هنگامی که این فایل را به مخزن github راه دور خود فشار دهید، github بلافاصله اجرای آزمایشی را شروع می کند. می توانید آن را در مخزن ارائه سرو من که شامل تمام کارهای درس های قبلی است ببینید: پیوند

توضیحات تصویر

می توانید اجرای آزمایشی github خود را در زیر عملیات مشاهده کنید. هنگامی که جریان خاصی را باز می کنید، گزارش آن و تمام خروجی اجرای آزمایشی را خواهید دید.

توضیحات تصویر

توضیحات تصویر

در بالا مثالی از اجرای برنامه ریزی شده است که من برای شروع هر یکشنبه در ساعت 10 صبح UTC تنظیم کردم.

فراموش نکنید که تمام کارهایی را که امروز انجام دادید در Github فشار دهید 😉 دستورات git را به خاطر دارید؟

git add .

git commit -am "add: qase and github actions support"

git push

کارگاه سرو قسمت 11 گزارش قاس، اقدامات Github

از اینکه این کارگاه را دنبال کردید متشکرم امیدوارم مفید بوده باشه برای هر سوالی، می‌دانید کجا می‌توانید مرا پیدا کنید: لینکدین من

کد تکمیل شده این درس

اگر چیز جدیدی یاد گرفتید با خرید یک قهوه از کار من حمایت کنید ☕

برای من یک قهوه بخر

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا