Skip to content

Vitest browser retry support + traces and screenshot automatic attachment on fail #1451

@Hideman42

Description

@Hideman42

Currently there is no retry support in browser mode it seem. We see the failure of the test but not the retry, only the last result somehow.
Note: On this subject I havent found yet how to bind the retryCount from test ctx to allure.

Additionally, it would be nice to have automatic attachment on tests failure.

EDIT: (1st version, check later one): Here is my current implementation as a starting point for built-in support:
import { getTestName } from '@vitest/runner/utils';
import { server } from 'vitest/browser';
import * as allure from 'allure-js-commons';

// In vite.config.ts
// commands: {
//   hostFileExists(_, path) {
//     return fs.existsSync(path);
//   },
// }

const sanitize = (str: string): string => str.replaceAll(/[^a-z0-9]/gi, '-');

beforeEach(ctx => {
  ctx.onTestFailed(async ({ task }) => {
    const prefix = `Attempt ${(task.result?.retryCount ?? 0) + 1} - `;
    await Promise.all([
      // Link the trace to allure (mostly based on internal sources of vitest cause functions not exposed and traces does not come in artifacts/attachments)
      (async (): Promise<void> => {
        const { retryCount = 0, repeatCount = 0 } = task.result ?? {};
        const testPath = task.file.filepath;

        const path = testPath.split('/');
        const fileName = path.pop();
        const tracePath = [
          ...path,
          '__traces__',
          fileName,
          `${sanitize(task.file.projectName ?? '')}-${sanitize(getTestName(task, '-'))}-${repeatCount}-${retryCount}.trace.zip`,
        ].join('/');

        // Validate trace exists before
        if (server.commands.hostFileExists(tracePath)) {
          console.info('Attaching', `${prefix}Trace.zip`, tracePath);
          await allure.attachmentPath(`${prefix}Trace.zip`, tracePath, 'application/zip');
        } else {
          console.log('No file for trace', tracePath);
        }
      })(),
      // All other vitest artifacts that we can support linking to allure
      ...task.artifacts.map(async artifact => {
        console.info('Artifact', artifact.type, artifact.attachments?.map(a => a.path));
        const artifactPrefix = `${prefix}${artifact.type.split(':').pop()} -`;
        if (artifact.type === 'internal:failureScreenshot') {
          for (const attachment of artifact.attachments) {
            const filename = artifactPrefix + (attachment.path.split('/').pop() ?? '');
            console.info('Attaching', filename, attachment.path);
            await allure.attachmentPath(filename, attachment.path, attachment.contentType as string);
          }
        }

        if (artifact.type === 'internal:toMatchScreenshot') {
          for (const attachment of artifact.attachments) {
            if (attachment.path) {
              const filename = artifactPrefix + (attachment.path.split('/').pop() ?? '');
              console.info('Attaching', filename, attachment.path);
              await allure.attachmentPath(filename, attachment.path, attachment.contentType as string);
            } else if (attachment.body) {
              const filename = `${prefix}${artifact.message} ${attachment.name}`;
              console.info('Attaching', filename, attachment.path);
              await allure.attachment(filename, attachment.body, attachment.contentType as string);
            }
          }
        }
      }),
    ]);

    // Clear artifacts after added to allure to avoid adding them twice after a retry
    task.artifacts.length = 0;
  });
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions