Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
- *install_corepack
- run:
name: Running tests
command: yarn test --maxWorkers=2
command: yarn test --pool=threads --poolOptions.threads.maxThreads=2

typecheck:
<<: *docker_defaults
Expand Down
16 changes: 0 additions & 16 deletions jest.config.js

This file was deleted.

14 changes: 5 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"prepareRelease": "npm run build && git add dist && npm run build:docs && git add docs",
"createChangelog": "conventional-changelog -p conventionalcommits && git add CHANGELOG.md",
"version": "npm run prepareRelease && npm run createChangelog",
"test": "jest --no-cache",
"test:dev": "jest --watch",
"test": "NODE_OPTIONS=--no-webstorage vitest run",
"test:dev": "NODE_OPTIONS=--no-webstorage vitest",
"typecheck": "tsc --noEmit",
"lint": "eslint",
"format": "prettier scripts src sample/src --write",
Expand All @@ -41,8 +41,6 @@
"@commitlint/cli": "21.2.1",
"@commitlint/config-conventional": "21.2.0",
"@eslint/js": "10.0.1",
"@testing-library/jest-dom": "^5.12.0",
"@types/jest": "30.0.0",
"@types/node": "^26.1.2",
"@typescript-eslint/eslint-plugin": "8.64.0",
"@typescript-eslint/parser": "8.64.0",
Expand All @@ -54,17 +52,15 @@
"eslint-config-prettier": "10.1.8",
"globals": "17.7.0",
"husky": "9.1.7",
"jest": "30.4.2",
"jest-environment-jsdom": "^30.4.1",
"jest-fetch-mock": "^3.0.3",
"jsdom": "^29.1.1",
"prettier": "3.9.5",
"process": "^0.11.10",
"stream-browserify": "^3.0.0",
"ts-jest": "29.4.12",
"typedoc": "^0.28.20",
"typescript": "6.0.3",
"vite": "^8.1.5",
"vite-plugin-node-polyfills": "^0.28.0"
"vite-plugin-node-polyfills": "^0.28.0",
"vitest": "^4.1.10"
},
"packageManager": "yarn@4.14.1"
}
1 change: 0 additions & 1 deletion scripts/jest/file-mock.ts

This file was deleted.

7 changes: 3 additions & 4 deletions scripts/jest/setup.ts → scripts/testSetup.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import '@testing-library/jest-dom';
import fetchMock from 'jest-fetch-mock';
import { TextEncoder } from 'util';
import { TextEncoder } from 'node:util';
import { webcrypto } from 'node:crypto';
import { fetchMock } from '../src/test-utils/mockFetch';

fetchMock.enableMocks();
global.fetch = fetchMock;

// JSDOM doesn't implement these, but browsers do
// [TextEncoder] https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { MY_ACCOUNT_DOMAINS } from '../../server-paths';
import { MY_ACCOUNT_DOMAINS } from '../../helpers/serverPaths';
import { MtLinkSdk } from '../..';
import authorizeUrl from '../authorize-url';
import { generateConfigs } from '../../helper';
import storage from '../../storage';
import expectUrlToMatchWithPKCE from '../../__tests__/helper/expect-url-to-match';
import authorizeUrl from './authorize-url';
import { generateConfigs } from '../../helpers';
import storage from '../../helpers/storage';
import expectUrlToMatchWithPKCE from '../../test-utils/expect-url-to-match';

jest.mock('../../storage');
vi.mock('../../helpers/storage');

describe('api', () => {
describe('authorize-url', () => {
const mockedStorage = jest.mocked(storage);
const mockedStorage = vi.mocked(storage);

const clientId = 'clientId';
const redirectUri = 'redirectUri';
Expand Down
14 changes: 10 additions & 4 deletions src/api/authorize-url.ts → src/api/authorize/authorize-url.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { constructScopes, generateConfigs, mergeConfigs, generateCodeChallenge, objectToQueryString } from '../helper';
import { MY_ACCOUNT_DOMAINS } from '../server-paths';
import { StoredOptions, AuthorizeUrlOptions } from '../typings';
import storage from '../storage';
import {
constructScopes,
generateConfigs,
mergeConfigs,
generateCodeChallenge,
objectToQueryString
} from '../../helpers';
import { MY_ACCOUNT_DOMAINS } from '../../helpers/serverPaths';
import { StoredOptions, AuthorizeUrlOptions } from '../../typings';
import storage from '../../helpers/storage';

export default async function authorize(
storedOptions: StoredOptions,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { MY_ACCOUNT_DOMAINS } from '../../server-paths';
import { MY_ACCOUNT_DOMAINS } from '../../helpers/serverPaths';
import { AuthorizeOptions, MtLinkSdk } from '../..';
import authorize from '../authorize';
import { generateConfigs } from '../../helper';
import * as helper from '../../helper';
import storage from '../../storage';
import expectUrlToMatchWithPKCE from '../../__tests__/helper/expect-url-to-match';
import authorize from './authorize';
import { generateConfigs } from '../../helpers';
import * as helper from '../../helpers';
import storage from '../../helpers/storage';
import expectUrlToMatchWithPKCE from '../../test-utils/expect-url-to-match';

jest.mock('../../storage');
vi.mock('../../helpers/storage');

describe('api', () => {
describe('authorize', () => {
const open = (window.open = jest.fn());
const open = (window.open = vi.fn());

const mockedStorage = jest.mocked(storage);
const mockedStorage = vi.mocked(storage);

const clientId = 'clientId';
const redirectUri = 'redirectUri';
Expand Down Expand Up @@ -186,7 +186,7 @@ describe('api', () => {
});

test('without window', async () => {
jest.spyOn(helper, 'hasWindow').mockReturnValue(false);
vi.spyOn(helper, 'hasWindow').mockReturnValue(false);

await expect(authorize(new MtLinkSdk().storedOptions)).rejects.toThrow(
'[mt-link-sdk] `authorize` only works in the browser.'
Expand Down
4 changes: 2 additions & 2 deletions src/api/authorize.ts → src/api/authorize/authorize.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getIsTabValue, hasWindow, openWindow } from '../helper';
import { StoredOptions, AuthorizeOptions } from '../typings';
import { getIsTabValue, hasWindow, openWindow } from '../../helpers';
import { StoredOptions, AuthorizeOptions } from '../../typings';
import authorizeUrl from './authorize-url';

export default async function authorize(storedOptions: StoredOptions, options: AuthorizeOptions = {}): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
declare const __VERSION__: string;

import fetch from 'jest-fetch-mock';
import { fetchMock, mockResponseOnce, mockRejectOnce } from '../../test-utils/mockFetch';

import { MY_ACCOUNT_DOMAINS } from '../../server-paths';
import { MY_ACCOUNT_DOMAINS } from '../../helpers/serverPaths';
import { MtLinkSdk } from '../..';
import exchangeToken from '../exchange-token';
import * as helper from '../../helper';
import exchangeToken from './exchange-token';
import * as helper from '../../helpers';

describe('api', () => {
beforeEach(() => {
vi.clearAllMocks();
});

describe('exchange-token', () => {
const clientId = 'clientId';
const code = 'code';
Expand Down Expand Up @@ -56,15 +60,14 @@ describe('api', () => {
});

test('make request', async () => {
fetch.mockClear();
fetch.mockResponseOnce(JSON.stringify(token));
mockResponseOnce(JSON.stringify(token));

await exchangeToken(mtLinkSdk.storedOptions, { code, codeVerifier: '' });

const url = `${MY_ACCOUNT_DOMAINS.production}/oauth/token.json`;

expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith(url, {
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand All @@ -81,10 +84,9 @@ describe('api', () => {
});

test('failed to request', async () => {
const error = 'failed';
const error = new Error('failed');

fetch.mockClear();
fetch.mockRejectedValueOnce(error);
mockRejectOnce(error);

await expect(exchangeToken(mtLinkSdk.storedOptions, { code, state, redirectUri })).rejects.toThrow(
`[mt-link-sdk] \`exchangeToken\` execution failed. ${error}`
Expand All @@ -94,31 +96,28 @@ describe('api', () => {
test('throw error on response with error', async () => {
const error = 'failed';

fetch.mockClear();
fetch.mockResponseOnce(JSON.stringify({ error: 'error', error_description: error }));
mockResponseOnce(JSON.stringify({ error: 'error', error_description: error }));

await expect(exchangeToken(mtLinkSdk.storedOptions, { code, state })).rejects.toThrow(error);
});

test('auto extract code from url query if no code was passed', async () => {
fetch.mockClear();
fetch.mockResponseOnce(JSON.stringify(token));
mockResponseOnce(JSON.stringify(token));

const code = 'realCode';

window.history.pushState({}, '', `?code=otherCode&code=${code}`);

await exchangeToken(mtLinkSdk.storedOptions, { state });

const result = fetch.mock.calls[0][1] || {};
const result = fetchMock.mock.calls[0][1] || {};
const data = JSON.parse(result.body as string);

expect(data.code).toBe(code);
});

test('auto extract state from url query if no state was passed or set during init', async () => {
fetch.mockClear();
fetch.mockResponseOnce(JSON.stringify(token));
mockResponseOnce(JSON.stringify(token));

window.history.pushState({}, '', `?state=otherState&state=${state}`);

Expand All @@ -128,7 +127,7 @@ describe('api', () => {
});

test('non browser environment will not auto extract code from url', async () => {
jest.spyOn(helper, 'hasWindow').mockReturnValue(false);
vi.spyOn(helper, 'hasWindow').mockReturnValue(false);

await expect(exchangeToken(mtLinkSdk.storedOptions)).rejects.toThrow(
'[mt-link-sdk] Missing option `code` in `exchangeToken`, or failed to get `code` from query/hash value from the URL.'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { generateSdkHeaderInfo, hasWindow, queryStringToObject } from '../helper';
import { MY_ACCOUNT_DOMAINS } from '../server-paths';
import { StoredOptions, ExchangeTokenOptions, Token } from '../typings';
import storage from '../storage';
import { generateSdkHeaderInfo, hasWindow, queryStringToObject } from '../../helpers';
import { MY_ACCOUNT_DOMAINS } from '../../helpers/serverPaths';
import { StoredOptions, ExchangeTokenOptions, Token } from '../../typings';
import storage from '../../helpers/storage';

function getCode(): string | undefined {
// not available in node environment
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { MY_ACCOUNT_DOMAINS } from '../../server-paths';
import { MY_ACCOUNT_DOMAINS } from '../../helpers/serverPaths';
import { MtLinkSdk } from '../..';
import logoutUrl from '../logout-url';
import { generateConfigs, objectToQueryString } from '../../helper';
import logoutUrl from './logout-url';
import { generateConfigs, objectToQueryString } from '../../helpers';

describe('api', () => {
describe('logout-url', () => {
Expand All @@ -16,7 +16,7 @@ describe('api', () => {
});

test('after calling init', async () => {
window.open = jest.fn();
window.open = vi.fn();

const clientId = 'clientId';
const cobrandClientId = 'cobrandClientId';
Expand All @@ -40,7 +40,7 @@ describe('api', () => {
});

test('with options', async () => {
window.open = jest.fn();
window.open = vi.fn();

const backTo = 'backTo';

Expand Down
6 changes: 3 additions & 3 deletions src/api/logout-url.ts → src/api/logout/logout-url.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { generateConfigs, mergeConfigs, objectToQueryString } from '../helper';
import { MY_ACCOUNT_DOMAINS } from '../server-paths';
import { StoredOptions, LogoutUrlOptions } from '../typings';
import { generateConfigs, mergeConfigs, objectToQueryString } from '../../helpers';
import { MY_ACCOUNT_DOMAINS } from '../../helpers/serverPaths';
import { StoredOptions, LogoutUrlOptions } from '../../typings';

export default async function logoutUrl(storedOptions: StoredOptions, options: LogoutUrlOptions = {}): Promise<string> {
const { clientId, mode, cobrandClientId, locale, samlSubjectId } = storedOptions;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { MY_ACCOUNT_DOMAINS } from '../../server-paths';
import { MY_ACCOUNT_DOMAINS } from '../../helpers/serverPaths';
import { MtLinkSdk } from '../..';
import logout from '../logout';
import { generateConfigs, objectToQueryString } from '../../helper';
import * as helper from '../../helper';
import logout from './logout';
import { generateConfigs, objectToQueryString } from '../../helpers';
import * as helper from '../../helpers';

describe('api', () => {
describe('logout', () => {
test('without calling init', async () => {
window.open = jest.fn();
window.open = vi.fn();

await logout(new MtLinkSdk().storedOptions);

Expand All @@ -19,7 +19,7 @@ describe('api', () => {
});

test('after calling init', async () => {
window.open = jest.fn();
window.open = vi.fn();

const clientId = 'clientId';
const cobrandClientId = 'cobrandClientId';
Expand All @@ -45,7 +45,7 @@ describe('api', () => {
});

test('with options', async () => {
window.open = jest.fn();
window.open = vi.fn();

const backTo = 'backTo';

Expand All @@ -61,7 +61,7 @@ describe('api', () => {
});

test('without window', async () => {
jest.spyOn(helper, 'hasWindow').mockReturnValue(false);
vi.spyOn(helper, 'hasWindow').mockReturnValue(false);

await expect(logout(new MtLinkSdk().storedOptions)).rejects.toThrow();
});
Expand Down
4 changes: 2 additions & 2 deletions src/api/logout.ts → src/api/logout/logout.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getIsTabValue, hasWindow, openWindow } from '../helper';
import { StoredOptions, LogoutOptions } from '../typings';
import { getIsTabValue, hasWindow, openWindow } from '../../helpers';
import { StoredOptions, LogoutOptions } from '../../typings';
import logoutUrl from './logout-url';

export default async function logout(storedOptions: StoredOptions, options: LogoutOptions = {}): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { MY_ACCOUNT_DOMAINS } from '../../server-paths';
import { MY_ACCOUNT_DOMAINS } from '../../helpers/serverPaths';
import { MtLinkSdk } from '../..';
import onboardUrl from '../onboard-url';
import { generateConfigs } from '../../helper';
import storage from '../../storage';
import expectUrlToMatchWithPKCE from '../../__tests__/helper/expect-url-to-match';
import onboardUrl from './onboard-url';
import { generateConfigs } from '../../helpers';
import storage from '../../helpers/storage';
import expectUrlToMatchWithPKCE from '../../test-utils/expect-url-to-match';

jest.mock('../../storage');
vi.mock('../../helpers/storage');

describe('api', () => {
describe('onboard-url', () => {
const mockedStorage = jest.mocked(storage);
const mockedStorage = vi.mocked(storage);

const clientId = 'clientId';
const redirectUri = 'redirectUri';
Expand Down
Loading