Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(tests): use vitest #376

Merged
merged 2 commits into from Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions .eslintrc.json
Expand Up @@ -5,8 +5,7 @@
"env": {
"browser": true,
"es2020": true,
"node": true,
"jest": true
"node": true
},
"parserOptions": {
"ecmaVersion": 11,
Expand Down
11 changes: 5 additions & 6 deletions bundle-tests/bundle-size.test.js
@@ -1,20 +1,19 @@
/* eslint @typescript-eslint/no-var-requires: "off" */

const fs = require("fs");
const { filesize } = require("filesize");
import { describe, test, expect } from "vitest";
import fs from "fs";
import { filesize } from "filesize";

const maxBundleSizeInKiloBytes = 4;
const maxLegacyBundleSizeInKiloBytes = 7.8;

describe("bundle size", () => {
it(`paypal-js.min.js should be less than ${maxBundleSizeInKiloBytes} KB`, () => {
test(`paypal-js.min.js should be less than ${maxBundleSizeInKiloBytes} KB`, () => {
const { size: sizeInBytes } = fs.statSync("dist/iife/paypal-js.min.js");
const [sizeInKiloBytes] = filesize(sizeInBytes, { output: "array" });

expect(sizeInKiloBytes).toBeLessThan(maxBundleSizeInKiloBytes);
});

it(`paypal-js.legacy.min.js should be less than ${maxLegacyBundleSizeInKiloBytes} KB`, () => {
test(`paypal-js.legacy.min.js should be less than ${maxLegacyBundleSizeInKiloBytes} KB`, () => {
const { size: sizeInBytes } = fs.statSync(
"dist/iife/paypal-js.legacy.min.js"
);
Expand Down
7 changes: 3 additions & 4 deletions bundle-tests/es3.test.js
@@ -1,12 +1,11 @@
/* eslint @typescript-eslint/no-var-requires: "off" */

const childProcess = require("child_process");
import { describe, test } from "vitest";
import childProcess from "child_process";

const command =
'npx eslint dist/iife/paypal-js.js dist/iife/paypal-js.legacy.js --no-eslintrc --parser-options="{ ecmaVersion: 3 }"';

describe("es3", () => {
it("should parse browser bundle using eslint's es3 parser", (done) => {
test("should parse browser bundle using eslint's es3 parser", (done) => {
childProcess.exec(command, (error, stdout, stderr) => {
if (error || stderr) {
console.log(error, stderr);
Expand Down
5 changes: 0 additions & 5 deletions jest.config.js

This file was deleted.

20,316 changes: 7,827 additions & 12,489 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions package.json
Expand Up @@ -15,13 +15,13 @@
"prerelease": "npm run validate",
"release": "standard-version --commit-all",
"postrelease": "git push && git push --follow-tags && npm run build && npm publish",
"test": "jest src",
"test:bundle": "jest bundle-tests/**",
"test": "vitest src",
"test:bundle": "vitest bundle-tests/**",
wsbrunson marked this conversation as resolved.
Show resolved Hide resolved
"test:e2e": "playwright test",
"test:e2e:debug": "PWDEBUG=1 playwright test --project=\"chromium\"",
"test:e2e:start": "node e2e-tests/http-server.js",
"typecheck": "tsc --noEmit",
"validate": "npm run check-node-version && npm run format:check && npm run typecheck && npm run build && npm run lint && npm test -- --coverage && npm run test:bundle"
"validate": "npm run check-node-version && npm run format:check && npm run typecheck && npm run build && npm run lint && npm test -- --coverage --watch=false && npm run test:bundle -- --watch=false"
},
"files": [
"dist",
Expand Down Expand Up @@ -52,24 +52,23 @@
"@rollup/plugin-replace": "5.0.2",
"@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-typescript": "11.0.0",
"@types/jest": "29.5.0",
"@types/node": "^18.15.10",
"@types/promise-polyfill": "6.0.4",
"@typescript-eslint/eslint-plugin": "5.57.0",
"@typescript-eslint/parser": "5.57.0",
"@vitest/coverage-c8": "^0.31.4",
"eslint": "8.36.0",
"filesize": "10.0.6",
"husky": "8.0.3",
"jest": "29.5.0",
"jest-environment-jsdom": "29.5.0",
"jsdom": "^22.1.0",
"lint-staged": "13.2.0",
"prettier": "2.8.7",
"rollup": "3.20.2",
"semver": "7.3.8",
"standard-version": "9.5.0",
"ts-jest": "29.0.5",
"tslib": "2.5.0",
"typescript": "5.0.2"
"typescript": "5.0.2",
"vitest": "^0.31.4"
},
"dependencies": {
"promise-polyfill": "^8.3.0"
Expand Down
6 changes: 3 additions & 3 deletions src/load-script.node.test.ts
@@ -1,6 +1,6 @@
/**
* @jest-environment node
*/
// @vitest-environment node

import { test, expect } from "vitest";

import { loadScript, loadCustomScript } from "./load-script";

Expand Down
43 changes: 15 additions & 28 deletions src/load-script.test.ts
@@ -1,9 +1,11 @@
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";

import { loadScript, loadCustomScript } from "./load-script";
// import using "*" to spy on insertScriptElement()
import * as utils from "./utils";

describe("loadScript()", () => {
const insertScriptElementSpy = jest.spyOn(utils, "insertScriptElement");
const insertScriptElementSpy = vi.spyOn(utils, "insertScriptElement");

const paypalNamespace = { version: "5" };

Expand Down Expand Up @@ -100,8 +102,7 @@ describe("loadScript()", () => {
});

describe("loadCustomScript()", () => {
const insertScriptElementSpy = jest.spyOn(utils, "insertScriptElement");
const PromiseBackup = window.Promise;
const insertScriptElementSpy = vi.spyOn(utils, "insertScriptElement");

beforeEach(() => {
document.head.innerHTML = "";
Expand All @@ -115,7 +116,6 @@ describe("loadCustomScript()", () => {

afterEach(() => {
insertScriptElementSpy.mockClear();
window.Promise = PromiseBackup;
});

test("should insert <script> and resolve the promise", async () => {
Expand Down Expand Up @@ -176,7 +176,7 @@ describe("loadCustomScript()", () => {

test("should throw the default error when the script fails to load but getting the error has a success response", async () => {
expect.assertions(2);
window.fetch = jest.fn().mockResolvedValue({
window.fetch = vi.fn().mockResolvedValue({
status: 200,
});

Expand Down Expand Up @@ -207,9 +207,9 @@ describe("loadCustomScript()", () => {
${errorMessage}

*/`;
window.fetch = jest.fn().mockResolvedValue({
window.fetch = vi.fn().mockResolvedValue({
status: 400,
text: jest.fn().mockResolvedValue(serverMessage),
text: vi.fn().mockResolvedValue(serverMessage),
});

insertScriptElementSpy.mockImplementation(({ onError }) => {
Expand All @@ -236,9 +236,9 @@ describe("loadCustomScript()", () => {
${errorMessage}

*/`;
window.fetch = jest.fn().mockResolvedValue({
window.fetch = vi.fn().mockResolvedValue({
status: 400,
text: jest.fn().mockResolvedValue(serverMessage),
text: vi.fn().mockResolvedValue(serverMessage),
});

insertScriptElementSpy.mockImplementation(({ onError }) => {
Expand All @@ -265,9 +265,9 @@ describe("loadCustomScript()", () => {
${errorMessage}

*/`;
window.fetch = jest.fn().mockResolvedValue({
window.fetch = vi.fn().mockResolvedValue({
status: 400,
text: jest.fn().mockResolvedValue(serverMessage),
text: vi.fn().mockResolvedValue(serverMessage),
});

insertScriptElementSpy.mockImplementation(({ onError }) => {
Expand All @@ -285,9 +285,9 @@ describe("loadCustomScript()", () => {
});

test("should throw an error when the script fails to load and fail fetching the error message", async () => {
window.fetch = jest.fn().mockResolvedValue({
window.fetch = vi.fn().mockResolvedValue({
status: 500,
text: jest.fn().mockResolvedValue("Internal Server Error"),
text: vi.fn().mockResolvedValue("Internal Server Error"),
});

insertScriptElementSpy.mockImplementation(({ onError }) => {
Expand All @@ -305,9 +305,9 @@ describe("loadCustomScript()", () => {
});

test("should use the provided promise ponyfill", () => {
const PromisePonyfill = jest.fn(() => {
const PromisePonyfill = vi.fn(() => {
return {
then: jest.fn(),
then: vi.fn(),
};
});
loadCustomScript(
Expand All @@ -319,17 +319,4 @@ describe("loadCustomScript()", () => {
);
expect(PromisePonyfill).toHaveBeenCalledTimes(1);
});

test("should throw an error when the Promise implementation is undefined", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admittedly, this is a bad test that had to delete the global Promise object. I ended up removing this test since I was unable to get it working with vitest.

I'm thinking we can actually get rid of this custom error message and just let the browser throw a standard error message in IE11 when window.Promise is undefined. https://github.com/paypal/paypal-js/blob/main/src/load-script.ts#L117-L119

// @ts-expect-error ignore deleting window.Promise
delete window.Promise;

expect(window.paypal).toBe(undefined);
expect(window.Promise).toBe(undefined);
expect(() =>
loadCustomScript({ url: "https://www.example.com/index.js" })
).toThrow(
"Promise is undefined. To resolve the issue, use a Promise polyfill."
);
});
});
38 changes: 21 additions & 17 deletions src/utils.test.ts
@@ -1,12 +1,14 @@
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";

vi.useFakeTimers();

import {
findScript,
insertScriptElement,
objectToQueryString,
processOptions,
} from "./utils";

jest.useFakeTimers();

describe("objectToQueryString()", () => {
test("coverts an object to a query string", () => {
const params = {
Expand Down Expand Up @@ -163,14 +165,16 @@ describe("insertScriptElement()", () => {
insertScriptElement({
url,
attributes: { "data-client-token": "12345" },
onError: jest.fn(),
onSuccess: jest.fn(),
onError: vi.fn(),
onSuccess: vi.fn(),
});

const scriptFromDOM =
document.querySelector<HTMLScriptElement>("head script");
if (!scriptFromDOM)

if (!scriptFromDOM) {
throw new Error("Expected to find <script> element");
}

expect(scriptFromDOM.src).toBe(url);
expect(scriptFromDOM.getAttribute("data-client-token")).toBe("12345");
Expand All @@ -180,8 +184,8 @@ describe("insertScriptElement()", () => {
insertScriptElement({
url,
attributes: { "data-csp-nonce": "12345" },
onError: jest.fn(),
onSuccess: jest.fn(),
onError: vi.fn(),
onSuccess: vi.fn(),
});

const scriptFromDOM =
Expand All @@ -203,8 +207,8 @@ describe("insertScriptElement()", () => {
const newScriptSrc = `${url}&currency=EUR`;
insertScriptElement({
url: newScriptSrc,
onError: jest.fn(),
onSuccess: jest.fn(),
onError: vi.fn(),
onSuccess: vi.fn(),
});

const [firstScript, secondScript] = Array.from(
Expand All @@ -219,7 +223,7 @@ describe("insertScriptElement()", () => {
const loadFailureSrcKey = "http://localhost/error";

beforeEach(() => {
const insertBeforeSpy = jest.spyOn(document.head, "insertBefore");
const insertBeforeSpy = vi.spyOn(document.head, "insertBefore");
interface MockHTMLScriptElement extends Node {
src: string;
onerror: () => void;
Expand All @@ -237,36 +241,36 @@ describe("insertScriptElement()", () => {
});

afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});

test("onload() event", () => {
expect.assertions(1);
const onloadMock = jest.fn();
const onloadMock = vi.fn();

const url = "https://www.paypal.com/sdk/js";
insertScriptElement({
url,
onError: jest.fn(),
onError: vi.fn(),
onSuccess: onloadMock,
});

jest.runAllTimers();
vi.runAllTimers();
expect(onloadMock).toBeCalled();
});

test("onerror() event", () => {
expect.assertions(1);
const onErrorMock = jest.fn();
const onErrorMock = vi.fn();
const url = loadFailureSrcKey;

insertScriptElement({
url,
onError: onErrorMock,
onSuccess: jest.fn(),
onSuccess: vi.fn(),
});

jest.runAllTimers();
vi.runAllTimers();
expect(onErrorMock).toBeCalled();
});
});
Expand Down
7 changes: 7 additions & 0 deletions vitest.config.ts
@@ -0,0 +1,7 @@
import { defineConfig } from "vitest/config";

export default defineConfig({
test: {
environment: "jsdom",
},
});