From e13326fd985f6f3bdca070de7de07fa7695251f4 Mon Sep 17 00:00:00 2001 From: shashwata Date: Sun, 18 Feb 2024 00:07:19 +0600 Subject: [PATCH] update suite --- .github/workflows/all-tests.yml | 1 + .github/workflows/e2e_api_tests.yml | 1 + tests/pw/.gitignore | 2 +- tests/pw/TODO.TS | 513 ------------------ tests/pw/TODO.md | 146 ++--- tests/pw/api.config.ts | 7 + tests/pw/pages/basePage.ts | 19 +- tests/pw/pages/requestForQuotationsPage.ts | 2 +- tests/pw/pages/storeReviewsPage.ts | 39 +- tests/pw/pages/storesPage.ts | 9 +- tests/pw/playwright.config.ts | 2 +- tests/pw/tests/api/_coverage.teardown.ts | 65 ++- .../{_env2.setup.spec.ts => _env2.setup.ts} | 0 tests/pw/tests/api/refunds.spec.ts | 2 +- tests/pw/tests/e2e/_env.setup.ts | 4 - tests/pw/tests/e2e/sellerBadges.spec.ts | 2 + tests/pw/tests/e2e/storeReviews.spec.ts | 6 +- tests/pw/types/environment.d.ts | 1 + tests/pw/utils/gitTestSummary.ts | 14 +- tests/pw/utils/summaryReporter.ts | 2 - 20 files changed, 194 insertions(+), 643 deletions(-) delete mode 100644 tests/pw/TODO.TS rename tests/pw/tests/api/{_env2.setup.spec.ts => _env2.setup.ts} (100%) diff --git a/.github/workflows/all-tests.yml b/.github/workflows/all-tests.yml index 380e00cd54..adc4974cb6 100644 --- a/.github/workflows/all-tests.yml +++ b/.github/workflows/all-tests.yml @@ -60,6 +60,7 @@ env: SYSTEM_INFO: ./tests/pw/playwright/systemInfo.json API_TEST_RESULT: ./tests/pw/playwright-report/api/summary-report/results.json E2E_TEST_RESULT: ./tests/pw/playwright-report/e2e/summary-report/results.json + API_COVERAGE: ./tests/pw/playwright-report/api/coverage-report/coverage.json jobs: tests: diff --git a/.github/workflows/e2e_api_tests.yml b/.github/workflows/e2e_api_tests.yml index 69eefeb5c2..248bfa97e5 100644 --- a/.github/workflows/e2e_api_tests.yml +++ b/.github/workflows/e2e_api_tests.yml @@ -58,6 +58,7 @@ env: SYSTEM_INFO: ./tests/pw/playwright/systemInfo.json API_TEST_RESULT: ./tests/pw/playwright-report/api/summary-report/results.json E2E_TEST_RESULT: ./tests/pw/playwright-report/e2e/summary-report/results.json + API_COVERAGE: ./tests/pw/playwright-report/api/coverage-report/coverage.json jobs: tests: diff --git a/tests/pw/.gitignore b/tests/pw/.gitignore index 6384be890a..ebd2671ae6 100644 --- a/tests/pw/.gitignore +++ b/tests/pw/.gitignore @@ -120,7 +120,7 @@ dist .tern-port # Stores VSCode versions used for testing VSCode extensions -.vscode/ +.vscode/settings.json .vscode-test # yarn v2 diff --git a/tests/pw/TODO.TS b/tests/pw/TODO.TS deleted file mode 100644 index 436c9aff95..0000000000 --- a/tests/pw/TODO.TS +++ /dev/null @@ -1,513 +0,0 @@ - - -// todo: export log test keep this, for wait for witch api is listed below - // await Promise.all([ - // this.page.waitForResponse((resp) => resp.url().includes(data.subUrls.api.dokan.logs) && resp.status() === 200), - // this.page.waitForResponse((resp) => resp.url().includes(data.subUrls.backend.dokan.downloadOrderLogs) && resp.status() === 200), - // this.page.locator(selector.admin.dokan.reports.allLogs.exportLogs).click() - // ]); - - - - -//********************************** tests to write ********************************** - -// todo: reverse withdraw : filter by calendar, do via vue locator -// todo: support ticket : filter by calendar -// todo: reports: filter by calendar on by day, by year, by vendor -// todo: all-logs : filter by calendar -// todo: vendor can send phone verification request -// todo: admin can approve phone verification request -// todo: need update to whole suite, merge both describe, update become customer tests -wholesale setting options tests - // todo: customer need or don't need approval : re-modify above two tests - // todo: only customer can see wholesale price - // todo: all users can see wholesale price - // todo: customer can purchase product at wholesale price - // todo: vendor can see Wholesale Price on Shop Archive - // todo: vendor can create wholesale product via api - -product advertisement - // todo: add search product advertisement by order - // todo: filter by calendar - -rfq - -// todo: create a generic function for below scenario on base page -await Promise.all([ - this.page.waitForResponse((resp) => resp.url().includes(data.subUrls.api.dokan.quotes) && resp.status() === 200), - this.page.waitForResponse((resp) => resp.url().includes(data.subUrls.api.dokan.products) && resp.status() === 200), - this.page.locator(selector.admin.dokan.requestForQuotation.quoteRules.newQuoteRule).click() -]); - -reports - // todo: filter by calendar - -vendor stuff - // todo: add tests for all permission group - // todo: add tests for email template - -verifications - // todo: need multiple verification request for admin, use db alteration - // todo: admin can disapprove verification request - // todo: add vendor tests - // todo: admin can approve phone verification request - -store review - // test('customer can edit store review @pro', async ( ) => { - // // todo: need separate method or update locator, ensure previous review exits - // await customer.reviewStore(data.predefined.vendorStores.vendor1, data.store); - // }); - - // todo: delete, restore, and permanently delete can be merged into one - - // todo: fix this clear filter not works - // await this.goIfNotThere(data.subUrls.backend.dokan.storeReviews); - // const clearIsVisible = await this.isVisible(selector.admin.dokan.storeReviews.filters.filterClear); - // if(clearIsVisible) { - // await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.filters.filterClear); - // } - -follow Store -// todo: need followers via api - - -seller badge - // test.skip('admin can filter vendors by seller badge @pro', async ( ) => { - // // todo: need to wait 1 min after badge create ; run via background process; can background process can be automated - // await admin.filterVendorsByBadge(data.sellerBadge.eventName.productsPublished); - // }); - - // test.skip('admin can view seller badge vendors @pro', async ( ) => { - // // todo: need to wait 1 min after badge create; run via background process ; can background process can be automated - // await admin.sellerBadgeVendors(data.sellerBadge.eventName.productsPublished); - // }); -stores spec -// test.beforeAll(async ({ browser, }) => { -// const adminContext = await browser.newContext(data.auth.adminAuth); -// aPage = await adminContext.newPage(); -// admin = new StoresPage(aPage); - // apiUtils = new ApiUtils(request); - // [,, storeName] = await apiUtils.createStore(payloads.createStore()); // todo: ues different store all stores -}); - -stores page -store on map -// storeName && await this.toBeVisible(selector.customer.cStoreList.map.storeOnMap.storeOnList(storeName)); // todo: need to update store settings via e2e to render on map for vendor1 - -products - // todo: import product - - -stores page - - // search vendor - async searchVendor(vendorName: string){ - await this.goIfNotThere(data.subUrls.backend.dokan.vendors); - await this.clearInputField(selector.admin.dokan.vendors.search); - await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.search, vendorName); - await this.toBeVisible(selector.admin.dokan.vendors.vendorCell(vendorName)); - - // negative scenario // todo: add this to all search also add flag to avoid this scenario - // await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.search, vendorName + 'abcdefgh'); - // await this.toBeVisible(selector.admin.dokan.vendors.noRowsFound); - - } - - setup('add test vendor orders @pro', async ({ request }) => { // todo: required for which test, might be replaced with create order with status - const apiUtils = new ApiUtils(request); - await apiUtils.createOrder(payloads.createProduct(), { ...payloads.createOrder, customer_id: CUSTOMER_ID }, payloads.vendorAuth); - }); - - - - // view auction product - async viewAuctionProduct(productName: string){ - await this.searchAuctionProduct(productName); - await this.hover(selector.vendor.vAuction.productCell(productName)); - await this.clickAndWaitForLoadState(selector.vendor.vAuction.view(productName)); - - // auction product elements are visible - const { bidQuantity, bidButton, ...viewAuction } = selector.vendor.vAuction.viewAuction; - await this.multipleElementVisible(viewAuction); - // todo: actual value can be asserted - } - - - - - - - - - - - - - - - - - - - - -api Suite - -api env -// setup.describe(' setup environment', () => { - -// // todo: remove this after : replacing admin as vendor -// setup('setup store settings @lite', async () => { -// const [response, ] = await apiUtils.put(endPoints.updateSettings, { data: payloads.setupStore }); -// expect(response.ok()).toBeTruthy(); -// }); - - -settings -// test.afterAll(async () => { -// todo: remove after update setting cause disable selling fix -// const [response, responseBody] = await apiUtils.put(endPoints.updateSettings, { data: payloads.setupStore }); -// expect(response.ok()).toBeTruthy(); -// expect(responseBody).toBeTruthy(); -// }); - - -refunds -test.beforeAll(async ({ request }) => { - apiUtils = new ApiUtils(request); - [, orderResponseBody,] = await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrder, 'wc-processing', payloads.vendorAuth); - [, refundId] = await dbUtils.createRefund(orderResponseBody); - // todo: dokan get all refunds dont recognize refunded by woocommerce, find out why & try to use refund by api instead of db - // [, refundId] = await apiUtils.createRefund(orderId, payloads.createRefund); // via woocommerce -}); - -reversewithdrawal - -test.beforeAll(async ({ request }) => { - apiUtils = new ApiUtils(request); - // check reverse withdrawal payment product exists // todo: add reverse withdraw check on setup - // await apiUtils.getReverseWithdrawalProductId(); // todo: failed on git action. payment product not created - // todo: add create product via admin after feature merged with pro - await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrderCod, 'wc-completed', payloads.vendorAuth); -}); - - - - -dbquery - - // execute db query - async dbQuery(query: string): Promise { - const dbContext: DbContext = new DbContext(mySql); - return await dbContext.inTransactionAsync(async (dbContext) => { // todo: grab connection failed actual reason, ambiguous error message - try{ - const result = await dbContext.executeAsync(query); - const res = JSON.parse(JSON.stringify(result)); - expect(res).not.toHaveProperty('errno'); // todo: ADD Actual ASSERT DB_QUERY IS SUCCESSES, update it - return res; - } - catch(err: unknown){ - // console.log('dbError:', err); - return err; - } - }); - }, - -dbdata -generalSettings: { - - //site settings - site_options: '', // todo: WHY EMPTY , value exists find out what - - // vendor store settings - vendor_store_options: '', // todo: WHY EMPTY -} - - - -basepage - -// todo: apply pseudo-style -// todo: add assertion to every base-page function -// todo: update every page method with locator method - // returns whether the element is visible - async isVisible(selector: string): Promise { - // return await this.isVisibleViaPage(selector); // todo: keep which one is better ; also update every page method with locator - return await this.isVisibleLocator(selector); - } - - // upload file - async uploadFile(selector: string, files: string | string[]): Promise { - // await this.page.setInputFiles(selector, files, { noWaitAfter: true }); - await this.page.setInputFiles(selector, files); - await this.wait(2); // todo: need to handle wait gracefully - } - -// assert element to contain text -async toContainText(selector: string, text: string){ - await expect(this.page.locator(selector)).toContainText(text); // todo: add lowercase for both expected and received - - - // assert element to be visible - // any of them , out of all, -async toBeVisibleAnyOfThem(selectors: string[],){ - const res = []; - for (const selector of selectors) { - res.push(await this.isVisible(selector)); - } - const result = res.includes(true); - expect(result).toBeTruthy(); - // todo: which elements are true for further operation -} - -async multipleElementVisible(selectors: any){ - - // todo: can also be merge with isVisible method and this method should support single selector too - // todo: implement for arrays - // selectors = Object.values(selectors); - // selectors.forEach( async (selector: string) => { - // // console.log(selector); - // await expect(this.page.locator(selector)).toBeVisible(); - // }); - - for (const selector in selectors ) { - // console.log(selectors[selector]); - // await expect(this.page.locator(selectors[selector])).toBeVisible(); - await this.toBeVisible(selectors[selector]); - } - -} - - - // delete element if exist (only first will delete) : dokan rma,report abuse - async deleteIfExists(selector: string): Promise { - // todo: there may be alternative solution, this method might not needed - const elementExists = await this.isVisible(selector); - if (elementExists) { - const element = this.page.locator(selector); - await element.click(); - } - } - - - - - // todo: urgent : update wait for multiple different response - // todo: urgent : update wait for multiple same response - - // // click & wait for multiple responses - // async clickAndWaitForResponses(subUrls: string[][], selector: string, code = 200): Promise { - // // // // const qrs: string[][] = [[data.subUrls.backend.quotes, '200'], [data.subUrls.backend.products, '200']]; - // // // const qrs: string[][] = [[data.subUrls.backend.quotes, '200']]; - // // await this.clickAndWaitForResponses(qrs, selector.admin.dokan.requestForQuotation.quoteRules.newQuoteRule); - // // const promises = []; - // // subUrls.forEach((subUrl) => { - // // console.log('subUls: ', subUrl[0], ' code: ', subUrl[1]); - // // // const promise = this.page.waitForResponse((resp) => resp.url().includes(subUrl[0] as string ) && resp.status() === (subUrl[1] ?? code)); - // // const promise = this.page.waitForResponse((resp) => resp.url().includes(subUrl[0]) && resp.status() === (subUrl[1])); - // // promises.push(promise); - // // }); - // // // promises.push(this.page.locator(selector).click()); - // // // const response = await Promise.all(promises); - // // await Promise.all([ - // // ...promises, - // // this.page.locator(selector).click() - // // ]); - // // return response; - // } - - // upload files when input file element is missing - async uploadFileViaListener(selector: string, files: string | string[]): Promise { - this.page.on('filechooser', async (fileChooser) => { await fileChooser.setFiles(files); }); - await this.page.locator(selector).click(); // invokes the filechooser // todo: convert with pormise all - - } - -// ********************************** woocommerce ********************************** - -// todo: implement this for checkbox assert await expect( page.locator( '#woocommerce_calc_taxes' ) ).toBeChecked(); - -// todo: reconsider that you need multiple assertion or not - // Verify that settings have been saved - await expect( - page.locator( '#setting-error-settings_updated' ) - ).toContainText( 'Permalink structure updated.' ); - await expect( page.locator( '#permalink_structure' ) ).toHaveValue( - '/%postname%/' - ); - await expect( - page.locator( '#woocommerce_permalink_structure' ) - ).toHaveValue( '/product/' ); - -// todo: follow woocommerce project structure like global setup, teardown, .... - -// todo: can implement test.step - -// todo: what is expect.poll - -await expect.poll( - async () => { - await page.goto( 'wp-admin/plugins.php', { - waitUntil: 'networkidle', - } ); - - return await updateCompleteMessage.isVisible(); - }, - { - intervals: [ 10_000 ], - timeout: 120_000, - } - ) - .toEqual( true ); - -// todo: try error.response.data - -let response = await axios( options ).catch( ( error ) => { - if ( error.response ) { - console.error( error.response.data ); - } - throw new Error( error.message ); -} ); - -// todo: use this for plugin download and activate scenario -response.data.pipe( fs.createWriteStream( zipFilePath ) ); - - - -// todo: use this for run command via code , built a utility function -export const installPluginThruWpCli = async ( pluginPath ) => { - const runWpCliCommand = async ( command ) => { - const { stdout, stderr } = await execAsync( - `pnpm exec wp-env run tests-cli "${ command }"` - ); - - console.log( stdout ); - console.error( stderr ); - }; - - - // todo: try & convert xpath to this - 'input:below(:text("Search for a product…"))', - // search for each product to add - await page.click( 'text=Search for a product…' ); - - - // Recalculate taxes - page.on( 'dialog', ( dialog ) => dialog.accept() ); - await page.click( 'text=Recalculate' ); - - - // todo: what is page.dispatchEvent - await page.goto( - 'wp-admin/admin.php?page=wc-settings&tab=shipping§ion=classes' - ); - - await page.dispatchEvent( - '.wc-shipping-class-delete >> nth=0', - 'click' - ); - await page.dispatchEvent( - '.wc-shipping-class-delete >> nth=0', - 'click' - ); - await page.dispatchEvent( 'text=Save shipping classes', 'click' ); - - - // todo: USe this for global setup, reporter or use two separate file for both suite -To expand on the process.env solution: - -// playwright.config.ts -const config = { - globalSetup: process.env.MODE === 'test' ? './test-global-setup.ts' : './production-global-setup.ts', - }; - export default config; - Run it like this: - - MODE=production npx playwright test - - - - - - - - - - - - -// todo: replace simple switch with below soln. - - 40 - -Neither, because both are quite verbose for a very simple task. You can just do: - -const result = ({ - 1: 'One', - 2: 'Two', - 3: 'Three' -})[opt] ?? 'Default' // opt can be 1, 2, 3 or anything (default) -This, of course, also works with strings, a mix of both or without a default case: - -const result = ({ - first: 'One', - 'sec-ond': 'Two', - 3: 'Three' -})[opt] // opt can be 'first', 'sec-ond' or 3 -Explanation: -It works by creating an object where the options/cases are the keys and the results are the values. By putting the option into the brackets you access the value of the key that matches the expression via the bracket notation. - -This returns undefined if the expression inside the brackets is not a valid key. We can detect this undefined-case by using the nullish coalescing operator ?? and return a default value. - - - - - // todo: this flags are not allowed in playwright project - // globalSetup: './global-setup', /* Path to the global setup file. This file will be required and run before all the tests. */ - // // globalTeardown: './global-teardown', /* Path to the global teardown file. This file will be required and run after all the tests. */ - // globalTimeout: process.env.CI ? 20 * (60 * 1000) : 20 * (60 * 1000), /* Maximum time in milliseconds the whole test suite can run */ - // maxFailures: process.env.CI ? 30 : 30, /* The maximum number of test failures for the whole test suite run. After reaching this number, testing will stop and exit with an error. */ - // preserveOutput: 'always', /* Whether to preserve test output in the testConfig.outputDir. Defaults to 'always'. */ - // forbidOnly: !!process.env.CI, /* Fail the build on CI if you accidentally left testonly in the source code. */ - // workers: process.env.CI ? 1 : 1, /* Opt out of parallel tests on CI. */ - // reportSlowTests: { max: 10, threshold: 20 }, /* Whether to report slow test files. Pass null to disable this feature. */ - // reporter: process.env.CI - // ? [ - // ['html', { open: 'never', outputFolder: 'playwright-report/api/html/html-report-api' }], - // ['junit', { outputFile: 'playwright-report/api/junit-report/api-results.xml' }], - // ['list', { printSteps: true }]] - // : [ - // ['html', { open: 'never', outputFolder: 'playwright-report/api/html/html-report-api' }], - // ['junit', { outputFile: 'playwright-report/api/junit-report/api-results.xml' }], - // ['list', { printSteps: true }], - // ['allure-playwright', { detail: true, outputFolder: 'playwright-report/api/allure/allure-report', suiteTitle: false }] - // ], - - -// todo: only for reference -test.use({ storageState: data.auth.adminAuthFile }); -test.use({ extraHTTPHeaders: { Authorization: payloads.adminAuth.Authorization } }); - - -// todo: implement this -// Define an array of endpoint URLs -const endpoints = [ - endPoints.getAllDokanEndpointsAdmin, - endPoints.getAllDokanEndpointsV1, - endPoints.getAllDokanEndpointsV2, - ]; - - // Function to fetch data from an API endpoint and extract routes and methods - async function fetchRoutesAndMethods(endpoint) { - const [, responseBody] = await apiUtils.get(endpoint); - return Object.entries(responseBody.routes).map(([route, { methods }]) => - methods.map((method) => `${method} ${route}`) - ); - } - - // Fetch data from all endpoints concurrently - const allRouteMethods = await Promise.all(endpoints.map(fetchRoutesAndMethods)); - - // Flatten the array and combine routes and methods - const coverageArray = allRouteMethods.flat(); diff --git a/tests/pw/TODO.md b/tests/pw/TODO.md index af11ae71c7..fe15d9e6e0 100644 --- a/tests/pw/TODO.md +++ b/tests/pw/TODO.md @@ -1,73 +1,89 @@ ### Todo: E2E-API TaskList -- [ ] Project: add more comments for code readability -- [ ] Project: add JSDOC -- [ ] Project: add parallelism for both git action & playwright tests -- [ ] Project: GRAB CONSOLE ERROR, And PHP ERROR -- [ ] TestData: update all image path from project root -- [ ] Zip_suite: add zip testing tests -- [ ] Selectors: add html tag to every css locator e.g. #id to input#id -- [ ] Selectors: shorten selector is all pages e.g. adminSettings = selector.admin.dokan.settings; -- [ ] Reporter: add os and browsers in env info -- [ ] Reporter: convert testSummary from commonjs module to es-module -- [ ] Readme: add readme contribute to e2e_api project -- [ ] Readme: rephrase readme -- [ ] Readme: fix bookmark issue -- [ ] Readme: update readme following readme guideline -- [ ] E2E_Suite: List all core tests and setup tests : plugins activated, wp settings, woocommerce settings, dokan modules activated , dokan settings for both e2e and api -- [ ] E2E_Suite: Slack integration -- [ ] E2E_Suite: Working-directory: ./path/to/tests -- [ ] E2E_Suite: Update auth if expired instead of every-time -- [ ] E2E_Suite: Report: separate two junit report showing on simple git-action summary -- [ ] E2E_Suite: Global setup & teardown can be converted to project setup: no need -- [ ] E2E_Suite: Project Configuration: separate everything for local & CI like: global setup, env, playwright config, Configure projects for multiple environments : ci, local, -- [ ] E2E_Suite: Fixture: add fixture: separate user role, implement fixture for lite pro issue handle -- [ ] E2E_Suite: Test basic auth can be used instead of cookies for authentication , no need to do this -- [ ] E2E_Suite: why two pages are opening : fix that -- [ ] E2E_Suite: Modal: Close modal if exists, causes issue with other tests where popup blocks next step**\*** -- [ ] E2E_Suite: add new tests or multiple entry in same test for all search parameter, i.e : by-customer, by-product, but-store,.. -- [ ] E2E_Suite: insert all date format according to site format , currently hardcoded to default format -> helpers.dateFormatFYJ -- [ ] E2E_Suite: try to fix product advertisement product, reverse withdraw product, store map save via api, currently e2e is used -- [ ] E2E_Suite: -// todo: Convert yml step to nodejs script for local development -// todo: Update goIfNotThere method usages: previous action add some changes but doesn't get reflected due to goIfNotThere -// todo: HANDLE ERROR: throw new Error('Badge is already published'); : either throw error or just return or convert to playwright error -// todo: Add modal or sub option to all explotory tesing -// todo: Add wait for multiple different response on base-page -// todo: Clear data in beforeAll where necessary - - - - - +- [ ] Project: add more comments for code readability +- [ ] Project: add JSDOC +- [ ] Project: GRAB CONSOLE ERROR, And PHP ERROR +- [ ] Zip_suite: add zip testing tests +- [ ] Selectors: shorten selector is all pages e.g. adminSettings = selector.admin.dokan.settings; +- [ ] Reporter: add os and browsers in env info +- [ ] Reporter: convert testSummary from commonjs module to es-module +- [ ] Readme: add readme contribute to e2e_api project +- [ ] Readme: rephrase readme +- [ ] Readme: fix bookmark issue +- [ ] Readme: update readme following readme guideline +- [ ] E2E_Suite: List all core tests and setup tests : plugins activated, wp settings, woocommerce settings, dokan modules activated , dokan settings for both e2e and api +- [ ] E2E_Suite: Slack integration +- [ ] E2E_Suite: Working-directory: ./path/to/tests +- [ ] E2E_Suite: Update auth if expired instead of every-time +- [ ] E2E_Suite: Report: separate two junit report showing on simple git-action summary +- [ ] E2E_Suite: Global setup & teardown can be converted to project setup: no need +- [ ] E2E_Suite: Project Configuration: separate everything for local & CI like: global setup, env, playwright config, Configure projects for multiple environments : ci, local, +- [ ] E2E_Suite: Fixture: add fixture: separate user role, implement fixture for lite pro issue handle +- [ ] E2E_Suite: Test basic auth can be used instead of cookies for authentication , no need to do this +- [ ] E2E_Suite: why two pages are opening : fix that +- [ ] E2E_Suite: Modal: Close modal if exists, causes issue with other tests where popup blocks next step***** +- [ ] E2E_Suite: add new tests or multiple entry in same test for all search parameter, i.e : by-customer, by-product, but-store,.. +- [ ] E2E_Suite: insert all date format according to site format , currently hardcoded to default format -> helpers.dateFormatFYJ +- [ ] E2E_Suite: try to fix product advertisement product, reverse withdraw product, store map save via api, currently e2e is used +- [ ] E2E_Suite: Convert yml step to nodejs script for local development +- [ ] E2E_Suite: Update goIfNotThere method usages: previous action add some changes but doesn't get reflected due to goIfNotThere +- [ ] E2E_Suite: HANDLE ERROR: throw new Error('Badge is already published'); : either throw error or just return or convert to playwright error +- [ ] E2E_Suite: Add modal or sub option to all explotory tesing +- [ ] E2E_Suite: Add wait for multiple different response on base-page +- [ ] E2E_Suite: Clear data in beforeAll where necessary +- [ ] E2E_Suite: reverse-withdraw: filter by calendar, do via vue locator +- [ ] E2E_Suite: support-ticket: filter by calendar +- [ ] E2E_Suite: reports: filter by calendar on by day, by year, by vendor +- [ ] E2E_Suite: all-logs: filter by calendar +- [ ] E2E_Suite: verification: vendor can send phone verification request +- [ ] E2E_Suite: verification: admin can approve phone verification request +- [ ] E2E_Suite: wholesale: customer need or don't need approval : re-modify above two tests +- [ ] E2E_Suite: wholesale: only customer can see wholesale price +- [ ] E2E_Suite: wholesale: all users can see wholesale price +- [ ] E2E_Suite: wholesale: customer can purchase product at wholesale price +- [ ] E2E_Suite: wholesale: vendor can see Wholesale Price on Shop Archive +- [ ] E2E_Suite: wholesale: vendor can create wholesale product via api +- [ ] E2E_Suite: advertisement: add search product advertisement by order +- [ ] E2E_Suite: advertisement: filter by calendar +- [ ] E2E_Suite: reports: filter by calendar +- [ ] E2E_Suite: vendor-stuff: add tests for all permission group +- [ ] E2E_Suite: vendor-stuff: add tests for email template +- [ ] E2E_Suite: verifications: need multiple verification request for admin, use db alteration +- [ ] E2E_Suite: verifications: admin can disapprove verification request +- [ ] E2E_Suite: verifications: add vendor tests +- [ ] E2E_Suite: verifications: admin can approve phone verification request +- [ ] E2E_Suite: follow-Store: need followers via api +- [ ] E2E_Suite: add multiple assertion to each test +- [ ] E2E_Suite: products: import product +- [ ] E2E_Suite: *** need custom check method causing multiple tests flaky +- [ ] E2E_Suite: add all email tests +- [ ] E2E_Suite: short browser context load in spec file +- [ ] E2E_Suite: use global variable instead of env variable +- [ ] E2E_Suite: todo: commission tests +- [ ] E2E_Suite: todo: add multi store category tests +- [ ] E2E_Suite: todo: move to other files: product categories +- [ ] E2E_Suite: todo: add multistep product categories test +- [ ] E2E_Suite: todo: add product categories settings test +- [ ] E2E_Suite: todo: add individual withdraw settings test +- [ ] E2E_Suite: todo: add separate files for catalog mode add new tests +- [ ] E2E_Suite: todo: add separate files for terms and conditions and add new tests +- [ ] E2E_Suite: todo: add multivendor payloads, and update create order for multivendor +- [ ] E2E_Suite: todo: add round option for helper methods +- [ ] API_Suite: make api suite independent, import: => like dokan pro exists or not, test summary, env setup from e2e suite +- [ ] API_Suite: add reverse withdraw and product advertisement on setup tests +- [ ] API_Suite: convert admin as vendor to vendor for whole suite +- [ ] API_Suite: add wait for multiple different response method +- [ ] API_Suite: add wait for multiple same response method +- [ ] API_Suite: fix rank math api +- [ ] API_Suite: update payloads which causes any php warning [create dokan issue where necessary] +- [ ] API_Suite: update all tests with product-id, customer-id, to make it faster +- [ ] API_Suite: hardcoding admin auth will hinder negative testing : test with invalid user +- [ ] API_Suite: Payload generator** +### In Progress +### Done ✓ -- [ ] E2E_Suite: \*\*\* need custom check method -- [ ] E2E_Suite: add all email tests -- [ ] E2E_Suite: short browser context load in spec file -- [ ] E2E_Suite: use global variable instead of env variable -- [ ] E2E_Suite: todo: commission tests -- [ ] E2E_Suite: todo: add multi store category tests -- [ ] E2E_Suite: todo: move to other files: product categories -- [ ] E2E_Suite: todo: add multistep product categories test -- [ ] E2E_Suite: todo: add product categories settings test -- [ ] E2E_Suite: todo: add individual withdraw settings test -- [ ] E2E_Suite: todo: add separate files for catalog mode add new tests -- [ ] E2E_Suite: todo: add separate files for terms and conditions and add new tests -- [ ] E2E_Suite: todo: add multivendor payloads, and update create order for multivendor -- [ ] E2E_Suite: todo: add round option for helper methods -- [ ] API_Suite: make api suite independent, import: => like dokan pro exists or not, test summary, env setup from e2e suite -- [ ] API_Suite: add reverse withdraw and product advertisement on setup tests -- [ ] API_Suite: convert admin as vendor to vendor for whole suite -- [ ] API_Suite: fix rank math api -- [ ] API_Suite: update payloads which causes any php warning [create dokan issue where necessary] -- [ ] API_Suite: update all tests with product-id, customer-id, to make it faster -- [ ] API_Suite: hardcoding admin auth will hinder negative testing : test with invalid user -- [ ] API_Suite: Payload generator\*\* -### In Progress - -### Done ✓ diff --git a/tests/pw/api.config.ts b/tests/pw/api.config.ts index a1cf441420..7b0b3f1bbe 100644 --- a/tests/pw/api.config.ts +++ b/tests/pw/api.config.ts @@ -86,9 +86,16 @@ export default defineConfig({ name: 'api_tests', testMatch: /.*\.spec\.ts/, dependencies: NO_SETUP ? [] : ['api_setup'] /* whether not to run setup tests before running actual tests */, + teardown: 'coverage_report', // teardown: 'global_teardown', }, + // coverage_report + { + name: 'coverage_report', + testMatch: '_coverage.teardown.ts', + }, + // global_teardown // { // name: 'global_teardown', diff --git a/tests/pw/pages/basePage.ts b/tests/pw/pages/basePage.ts index 7f214dba50..99cb765037 100644 --- a/tests/pw/pages/basePage.ts +++ b/tests/pw/pages/basePage.ts @@ -240,6 +240,20 @@ export class BasePage { return response; } + // click & wait for multiple responses + async clickAndWaitForMultipleResponses(subUrls: string[][], selector: string, code = 200): Promise { + // todo: fix this; also update for same and different subUrls + const promises = []; + subUrls.forEach(subUrl => { + console.log('subUls: ', subUrl[0], ' code: ', subUrl[1]); + const promise = this.page.waitForResponse(resp => resp.url().includes(subUrl[0] as string) && resp.status() === (subUrl[1] ?? code)); + promises.push(promise); + }); + promises.push(this.page.locator(selector).click()); + const response = await Promise.all([...promises, this.page.locator(selector).click()]); + return response; + } + // click & accept async clickAndAccept(selector: string): Promise { await Promise.all([this.acceptAlert(), this.page.locator(selector).click()]); @@ -754,7 +768,7 @@ export class BasePage { async uploadFile(selector: string, files: string | string[]): Promise { // await this.page.setInputFiles(selector, files, { noWaitAfter: true }); await this.page.setInputFiles(selector, files); - await this.wait(1.5); + await this.wait(1.5); //todo: resolve this } // upload file @@ -1306,13 +1320,14 @@ export class BasePage { // assert any element to be visible async toBeVisibleAnyOfThem(selectors: string[]) { - // todo: extend nd improve this method + // todo: extend and improve this method const res = []; for (const selector of selectors) { res.push(await this.isVisible(selector)); } const result = res.includes(true); expect(result).toBeTruthy(); + // todo: return which elements are true for further operation } // assert element to be visible diff --git a/tests/pw/pages/requestForQuotationsPage.ts b/tests/pw/pages/requestForQuotationsPage.ts index 9b6fa19a62..103d09d08d 100644 --- a/tests/pw/pages/requestForQuotationsPage.ts +++ b/tests/pw/pages/requestForQuotationsPage.ts @@ -70,7 +70,7 @@ export class RequestForQuotationsPage extends AdminPage { // add quote rule async addQuoteRule(rule: requestForQuotation['quoteRule']) { await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuoteRules); - + //todo : move to base page await Promise.all([ this.page.waitForResponse(resp => resp.url().includes(data.subUrls.api.dokan.quotes) && resp.status() === 200), this.page.waitForResponse(resp => resp.url().includes(data.subUrls.api.dokan.products) && resp.status() === 200), diff --git a/tests/pw/pages/storeReviewsPage.ts b/tests/pw/pages/storeReviewsPage.ts index ee782c82ec..9fc4befee8 100644 --- a/tests/pw/pages/storeReviewsPage.ts +++ b/tests/pw/pages/storeReviewsPage.ts @@ -65,30 +65,31 @@ export class StoreReviewsPage extends AdminPage { await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.editReview.update); } - // delete store review - async deleteStoreReview() { + async updateStoreReview(action: string) { await this.goto(data.subUrls.backend.dokan.storeReviews); - await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); - await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.storeReviewDelete); - } - // restore store review - async restoreStoreReview() { - await this.goto(data.subUrls.backend.dokan.storeReviews); - // await this.goIfNotThere(data.subUrls.backend.dokan.storeReviews); - await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.navTabs.trash); + switch (action) { + case 'trash': + await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.storeReviewDelete); + break; - await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); - await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.storeReviewRestore); - } + case 'permanently-delete': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.navTabs.trash); + await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.storeReviewPermanentlyDelete); - // permanently delete store review - async permanentlyDeleteStoreReview() { - await this.goto(data.subUrls.backend.dokan.storeReviews); - await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.navTabs.trash); + break; - await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); - await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.storeReviewPermanentlyDelete); + case 'restore': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.navTabs.trash); + await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.storeReviewRestore); + break; + + default: + break; + } } // store reviews bulk action diff --git a/tests/pw/pages/storesPage.ts b/tests/pw/pages/storesPage.ts index 281b565a95..30ae385906 100644 --- a/tests/pw/pages/storesPage.ts +++ b/tests/pw/pages/storesPage.ts @@ -296,17 +296,18 @@ export class StoresPage extends AdminPage { } // search vendor - async searchVendor(vendorName: string) { + async searchVendor(vendorName: string, neg: boolean = false) { await this.goIfNotThere(data.subUrls.backend.dokan.vendors); await this.clearInputField(selector.admin.dokan.vendors.search); - await this.typeAndWaitForResponseAndLoadState(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.search, vendorName); await this.toBeVisible(selector.admin.dokan.vendors.vendorCell(vendorName)); // negative scenario - // await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.search, vendorName + 'abcdefgh'); - // await this.toBeVisible(selector.admin.dokan.vendors.noRowsFound); + if (neg) { + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.search, vendorName + 'abcdefgh'); + await this.toBeVisible(selector.admin.dokan.vendors.noRowsFound); + } } // update vendor diff --git a/tests/pw/playwright.config.ts b/tests/pw/playwright.config.ts index 4331d8692d..574d9cfd0f 100644 --- a/tests/pw/playwright.config.ts +++ b/tests/pw/playwright.config.ts @@ -9,7 +9,7 @@ export default defineConfig({ /* Folder for test artifacts such as screenshots, videos, traces, etc. */ outputDir: 'playwright/test-artifacts/', /* Path to the global setup file. This file will be required and run before all the tests. */ - globalSetup: './global-setup', + // globalSetup: './global-setup', /* Path to the global teardown file. This file will be required and run after all the tests. */ // globalTeardown : './global-teardown', /* Maximum time in milliseconds the whole test suite can run */ diff --git a/tests/pw/tests/api/_coverage.teardown.ts b/tests/pw/tests/api/_coverage.teardown.ts index 35ac733cf7..f9c95ea62f 100644 --- a/tests/pw/tests/api/_coverage.teardown.ts +++ b/tests/pw/tests/api/_coverage.teardown.ts @@ -3,8 +3,11 @@ import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { helpers } from '@utils/helpers'; import { execSync } from 'child_process'; +import fs from 'fs'; +import path from 'path'; test.describe('get api test coverage', () => { + const outputFile = 'playwright-report/api/coverage-report/coverage.json'; let apiUtils: ApiUtils; test.beforeAll(async () => { @@ -16,45 +19,57 @@ test.describe('get api test coverage', () => { }); test('get coverage', async () => { - const [, responseBody1] = await apiUtils.get(endPoints.getAllDokanEndpointsAdmin); - const [, responseBody2] = await apiUtils.get(endPoints.getAllDokanEndpointsV1); - const [, responseBody3] = await apiUtils.get(endPoints.getAllDokanEndpointsV2); - const allRoutes = [...Object.keys(responseBody1.routes), ...Object.keys(responseBody2.routes), ...Object.keys(responseBody3.routes)]; - // const allRoutes = [ ...Object.keys(responseBody3.routes)]; - const allRouteObjValues = [...Object.values(responseBody1.routes), ...Object.values(responseBody2.routes), ...Object.values(responseBody3.routes)]; - // const allRouteObjValues = [ ...Object.values(responseBody3.routes)]; + const endpoints = [endPoints.getAllDokanEndpointsAdmin, endPoints.getAllDokanEndpointsV1, endPoints.getAllDokanEndpointsV2]; + const allRoutes: string[] = []; + const allRouteObjValues = []; + for (const endpoint of endpoints) { + const [, responseBody] = await apiUtils.get(endpoint); + allRoutes.push(...Object.keys(responseBody.routes)); + allRouteObjValues.push(...Object.values(responseBody.routes)); + } const allRouteMethods: string[][] = allRouteObjValues.map(route => route.methods); - // console.log(allRoutes); - // console.log(allRouteMethods); let coverageArray = allRouteMethods.flatMap((methods, i) => methods.map(method => `${method} ${allRoutes[i]}`)); coverageArray = [...new Set(coverageArray)]; coverageArray = coverageArray.filter(e => !e.includes('PATCH')); // console.log(coverageArray); - console.log(coverageArray.length); - getCoverage(coverageArray); + // console.log(coverageArray.length); + + getCoverage(coverageArray, outputFile); }); }); -function getCoverage(coverageArray: any[]) { +function getCoverage(coverageArray: any[], outputFile?: string) { + const coverageReport: any = { + total_endpoints: 0, + covered_endpoints: 0, + coverage: 0, + uncovered_Endpoints: [], + }; + const totalEndPoints = coverageArray.length; let coveredEndPoints = 0; - const nonCoveredEndpoints: string[] = []; + const uncoveredEndpoints: string[] = []; //Iterates through the coverageArray to grep each file in the test directory looking for matches for (const route of coverageArray) { const pattern = `COVERAGE_TAG: ${helpers.escapeRegex(route)}$`; const output = execSync(`grep -irl -E '${pattern}' tests/api | cat `, { encoding: 'utf-8' }); - // console.log('route: ', pattern); - // console.log('grep_Output: ', output); - if (output.toString() != '') { - coveredEndPoints += 1; - } else { - console.log(`Endpoint with no coverage: ${route}`); - nonCoveredEndpoints.push(route); - } + output.toString() != '' ? (coveredEndPoints += 1) : uncoveredEndpoints.push(route); } + const percentCovered = Number(((coveredEndPoints / totalEndPoints) * 100).toFixed(2)); - const percentCovered = ((coveredEndPoints / totalEndPoints) * 100).toFixed(2); - console.log('Total Endpoints: ' + totalEndPoints); - console.log('Covered Endpoints: ' + coveredEndPoints); - console.log('Coverage: ' + percentCovered + '%'); + if (outputFile) { + coverageReport.total_endpoints = totalEndPoints; + coverageReport.covered_endpoints = coveredEndPoints; + coverageReport.coverage = percentCovered; + coverageReport.uncovered_Endpoints = uncoveredEndpoints; + if (!fs.existsSync(path.dirname(outputFile))) { + fs.mkdirSync(path.dirname(outputFile), { recursive: true }); + } + fs.writeFileSync(outputFile, JSON.stringify(coverageReport)); + } else { + console.log('Uncovered Endpoints: ', uncoveredEndpoints); + console.log('Total Endpoints: ' + totalEndPoints); + console.log('Covered Endpoints: ' + coveredEndPoints); + console.log('Coverage: ' + percentCovered + '%'); + } } diff --git a/tests/pw/tests/api/_env2.setup.spec.ts b/tests/pw/tests/api/_env2.setup.ts similarity index 100% rename from tests/pw/tests/api/_env2.setup.spec.ts rename to tests/pw/tests/api/_env2.setup.ts diff --git a/tests/pw/tests/api/refunds.spec.ts b/tests/pw/tests/api/refunds.spec.ts index 75d5c78f2d..ac51bd0647 100644 --- a/tests/pw/tests/api/refunds.spec.ts +++ b/tests/pw/tests/api/refunds.spec.ts @@ -19,7 +19,7 @@ test.describe('refunds api test', () => { test.beforeAll(async () => { apiUtils = new ApiUtils(await request.newContext()); [, orderResponseBody] = await apiUtils.createOrderWithStatus(payloads.createProduct(), payloads.createOrder, 'wc-processing', payloads.vendorAuth); - [, refundId] = await dbUtils.createRefundRequest(orderResponseBody); + [, refundId] = await dbUtils.createRefundRequest(orderResponseBody); // todo: replace by woocommerce api }); test.afterAll(async () => { diff --git a/tests/pw/tests/e2e/_env.setup.ts b/tests/pw/tests/e2e/_env.setup.ts index 57302f2470..b427663b18 100644 --- a/tests/pw/tests/e2e/_env.setup.ts +++ b/tests/pw/tests/e2e/_env.setup.ts @@ -161,10 +161,6 @@ setup.describe('setup user settings', () => { await apiUtils.createProduct({ ...product, status: 'pending', in_stock: true }, payloads.vendorAuth); await apiUtils.createProduct({ ...product, status: 'publish', in_stock: true }, payloads.vendorAuth); }); - - setup.skip('add test vendor orders @lite', async () => { - await apiUtils.createOrder(payloads.createProduct(), { ...payloads.createOrder, customer_id: CUSTOMER_ID }, payloads.vendorAuth); - }); }); setup.describe('setup dokan settings', () => { diff --git a/tests/pw/tests/e2e/sellerBadges.spec.ts b/tests/pw/tests/e2e/sellerBadges.spec.ts index 6f0cb253bb..8c73c090b8 100644 --- a/tests/pw/tests/e2e/sellerBadges.spec.ts +++ b/tests/pw/tests/e2e/sellerBadges.spec.ts @@ -54,10 +54,12 @@ test.describe('Seller badge test', () => { }); test.skip('admin can filter vendors by seller badge @pro @a', async () => { + // todo: need to wait 1 min after badge create; run via background process; await admin.filterVendorsByBadge(data.sellerBadge.eventName.productsPublished); }); test.skip('admin can view seller badge vendors @pro @a', async () => { + // todo: need to wait 1 min after badge create; run via background process; await admin.sellerBadgeVendors(data.sellerBadge.eventName.productsPublished); }); diff --git a/tests/pw/tests/e2e/storeReviews.spec.ts b/tests/pw/tests/e2e/storeReviews.spec.ts index 346e910f48..4a87ce0c29 100644 --- a/tests/pw/tests/e2e/storeReviews.spec.ts +++ b/tests/pw/tests/e2e/storeReviews.spec.ts @@ -58,15 +58,15 @@ test.describe('Store Reviews test', () => { }); test('admin can delete store review @pro @a', async () => { - await admin.deleteStoreReview(); + await admin.updateStoreReview('trash'); }); test('admin can restore deleted store review @pro @a', async () => { - await admin.restoreStoreReview(); + await admin.updateStoreReview('permanently-delete'); }); test('admin can permanently delete store review @pro @a', async () => { - await admin.permanentlyDeleteStoreReview(); + await admin.updateStoreReview('restore'); }); test('admin can perform store reviews bulk action @pro @a', async () => { diff --git a/tests/pw/types/environment.d.ts b/tests/pw/types/environment.d.ts index f97a7692bb..c4379bb438 100644 --- a/tests/pw/types/environment.d.ts +++ b/tests/pw/types/environment.d.ts @@ -41,6 +41,7 @@ declare global { DB_PREFIX: string; API_TEST_RESULT: string; E2E_TEST_RESULT: string; + API_COVERAGE: string; } } } diff --git a/tests/pw/utils/gitTestSummary.ts b/tests/pw/utils/gitTestSummary.ts index 0b3bfe5b7c..0f8e33562b 100644 --- a/tests/pw/utils/gitTestSummary.ts +++ b/tests/pw/utils/gitTestSummary.ts @@ -1,5 +1,5 @@ const fs = require('fs'); -const { SHA, PR_NUMBER, SYSTEM_INFO, API_TEST_RESULT, E2E_TEST_RESULT } = process.env; +const { SHA, PR_NUMBER, SYSTEM_INFO, API_TEST_RESULT, E2E_TEST_RESULT, API_COVERAGE } = process.env; const replace = obj => Object.keys(obj).forEach(key => (typeof obj[key] == 'object' ? replace(obj[key]) : (obj[key] = String(obj[key])))); const readFile = filePath => (fs.existsSync(filePath) ? JSON.parse(fs.readFileSync(filePath, 'utf8')) : false); @@ -13,18 +13,28 @@ const getTestResult = (suiteName, filePath) => { return testSummary; }; +const getCoverageReport = filePath => { + const coverageReport = readFile(filePath); + if (!coverageReport) { + return []; + } + return coverageReport.coverage; +}; + const addSummaryHeadingAndTable = core => { const tableHeader = [ { data: 'Test :test_tube:', header: true }, { data: 'Total :bar_chart:', header: true }, { data: 'Passed :white_check_mark:', header: true }, { data: 'Failed :rotating_light:', header: true }, - { data: 'Flaky :construction:', header: true }, + { data: 'Flaky :warning:', header: true }, { data: 'Skipped :next_track_button:', header: true }, { data: 'Duration :alarm_clock:', header: true }, + { data: 'Coverage :checkered_flag:', header: true }, ]; const apiTesResult = getTestResult('API Tests', API_TEST_RESULT); const e2eTesResult = getTestResult('E2E Tests', E2E_TEST_RESULT); + apiTesResult.push(getCoverageReport(API_COVERAGE)); core.summary.addHeading('Tests Summary').addRaw(`Commit SHA: ${SHA}`).addBreak().addBreak().addTable([tableHeader, apiTesResult, e2eTesResult]); }; diff --git a/tests/pw/utils/summaryReporter.ts b/tests/pw/utils/summaryReporter.ts index 353a3f4dd7..6cae817671 100644 --- a/tests/pw/utils/summaryReporter.ts +++ b/tests/pw/utils/summaryReporter.ts @@ -78,8 +78,6 @@ export default class summaryReport implements Reporter { summary.skipped = results.filter(x => x === 'skipped').length; // console.log(summary); - // fs.writeFileSync('results.json', JSON.stringify(summary)); - if (this.options.outputFile) { const outputFile = this.options.outputFile; if (!fs.existsSync(path.dirname(outputFile))) {