зеркало из https://github.com/mozilla/fxa.git
chore(deps): upgrade react-scripts and webpack to v5
Because: - we want to upgrade our React/CRA packages to react-scripts and webpack v5 This commit: - upgrades react-scripts and webpack to v5 for Settings, Payments, and Admin Panel - upgrades other dependencies in order to make the react-scripts and webpack upgrades work - hybridizes fxa-auth-client and fxa-shared into dual module format packages
This commit is contained in:
Родитель
049ec6cb4c
Коммит
a0b2cda909
|
@ -88,7 +88,9 @@
|
|||
"@nx/jest": "16.3.1",
|
||||
"@nx/js": "^16.3.1",
|
||||
"@nx/node": "^16.3.1",
|
||||
"@nx/workspace": "^16.3.1",
|
||||
"@nx/workspace": "16.3.1",
|
||||
"@storybook/html-webpack5": "^7.0.23",
|
||||
"@storybook/react-webpack5": "^7.0.23",
|
||||
"@types/jest": "^29.5.1",
|
||||
"@types/mysql": "^2",
|
||||
"@types/node": "^18.16.1",
|
||||
|
@ -117,10 +119,15 @@
|
|||
"packages/*"
|
||||
],
|
||||
"resolutions": {
|
||||
"@babel/core": "^7.22.5",
|
||||
"@babel/helper-module-imports": "^7.22.5",
|
||||
"@babel/types": "^7.22.5",
|
||||
"@grpc/grpc-js": "~1.6.0",
|
||||
"@nestjs/cli/typescript": "^4.5.2",
|
||||
"@svgr/webpack": "^8.0.1",
|
||||
"@types/node": "^18.14.2",
|
||||
"browserid-crypto": "https://github.com/mozilla-fxa/browserid-crypto.git#5979544d13eeb15a02d0b9a6a7a08a698d54d37d",
|
||||
"css-minimizer-webpack-plugin": ">=4 <5",
|
||||
"elliptic": ">=6.5.4",
|
||||
"eslint-plugin-import": "^2.25.2",
|
||||
"fbjs/isomorphic-fetch": "^3.0.0",
|
||||
|
|
|
@ -10,9 +10,10 @@ const CI = !!process.env.CI;
|
|||
// see .vscode/launch.json
|
||||
const DEBUG = !!process.env.DEBUG;
|
||||
const SLOWMO = parseInt(process.env.PLAYWRIGHT_SLOWMO || '0');
|
||||
const NUM_WORKERS = parseInt(process.env.PLAYWRIGHT_WORKERS || '2');
|
||||
|
||||
let retries = 0,
|
||||
workers = 2,
|
||||
workers = NUM_WORKERS || 2,
|
||||
maxFailures = 0;
|
||||
if (CI) {
|
||||
// Overall maxFailures is now dependent on the number of retries, workers
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
"react": "^16.13.0",
|
||||
"react-dom": "^16.13.0",
|
||||
"react-router-dom": "^6.9.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-scripts": "^5.0.1",
|
||||
"serve-static": "^1.14.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -90,6 +90,7 @@
|
|||
"tailwindcss": "^3.3.1",
|
||||
"tailwindcss-textshadow": "^2.1.3",
|
||||
"ts-jest": "^29.1.0",
|
||||
"typescript": "^4.9.3"
|
||||
"typescript": "^4.9.3",
|
||||
"webpack": "^5.84.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import App from './App';
|
||||
import { mockConfigBuilder } from './lib/config';
|
||||
import {
|
||||
|
@ -11,6 +10,7 @@ import {
|
|||
AdminPanelGroup,
|
||||
AdminPanelGuard,
|
||||
} from 'fxa-shared/guards';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
it('renders without imploding', () => {
|
||||
const guard = new AdminPanelGuard(AdminPanelEnv.Prod);
|
||||
|
@ -21,6 +21,8 @@ it('renders without imploding', () => {
|
|||
group: guard.getGroup(AdminPanelGroup.SupportAgentProd),
|
||||
},
|
||||
});
|
||||
const { queryByTestId } = render(<App {...{ config }} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<App {...{ config }} />
|
||||
);
|
||||
expect(queryByTestId('app')).toBeInTheDocument();
|
||||
});
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import Subscription from '.';
|
||||
import { MozSubscription } from 'fxa-admin-server/src/graphql';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
const subscription: MozSubscription = {
|
||||
created: 1583259953 * 1e3,
|
||||
|
@ -24,7 +25,7 @@ const subscription: MozSubscription = {
|
|||
};
|
||||
|
||||
it('renders each field as expected', () => {
|
||||
render(<Subscription {...subscription} />);
|
||||
renderWithLocalizationProvider(<Subscription {...subscription} />);
|
||||
|
||||
screen.getByText(subscription.productName);
|
||||
screen.getByText(subscription.status);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import PageRelyingParties from '.';
|
||||
import {
|
||||
|
@ -20,6 +20,7 @@ import {
|
|||
AdminPanelGuard,
|
||||
} from '../../../../fxa-shared/guards';
|
||||
import { mockConfigBuilder } from '../../lib/config';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
// Setup the current user hook. Required for Guards.
|
||||
const mockGuard = new AdminPanelGuard(AdminPanelEnv.Prod);
|
||||
|
@ -43,7 +44,7 @@ jest.mock('../../hooks/UserContext.ts', () => ({
|
|||
}));
|
||||
|
||||
it('renders without imploding and shows loading text', () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<MockedProvider mocks={[mockGetRelyingParties()]} addTypename={false}>
|
||||
<PageRelyingParties />
|
||||
</MockedProvider>
|
||||
|
@ -54,7 +55,7 @@ it('renders without imploding and shows loading text', () => {
|
|||
});
|
||||
|
||||
it('renders as expected with zero relying parties', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<MockedProvider mocks={[mockGetRelyingParties()]} addTypename={false}>
|
||||
<PageRelyingParties />
|
||||
</MockedProvider>
|
||||
|
@ -63,7 +64,7 @@ it('renders as expected with zero relying parties', async () => {
|
|||
});
|
||||
|
||||
it('renders as expected with a relying party containing all fields', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<MockedProvider
|
||||
mocks={[mockGetRelyingParties([MOCK_RP_ALL_FIELDS])]}
|
||||
addTypename={false}
|
||||
|
@ -81,7 +82,7 @@ it('renders as expected with a relying party containing all fields', async () =>
|
|||
});
|
||||
|
||||
it('updates notes', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<MockedProvider
|
||||
mocks={[
|
||||
mockGetRelyingParties([MOCK_RP_ALL_FIELDS]),
|
||||
|
@ -109,7 +110,7 @@ it('updates notes', async () => {
|
|||
});
|
||||
|
||||
it('shows error if notes fail to update', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<MockedProvider
|
||||
mocks={[
|
||||
mockGetRelyingParties([MOCK_RP_ALL_FIELDS]),
|
||||
|
@ -137,7 +138,7 @@ it('shows error if notes fail to update', async () => {
|
|||
});
|
||||
|
||||
it('renders as expected with a relying party containing falsy fields', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<MockedProvider
|
||||
mocks={[mockGetRelyingParties([MOCK_RP_FALSY_FIELDS])]}
|
||||
addTypename={false}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# A JavaScript Client for Firefox Accounts
|
||||
|
||||
### Dual Package
|
||||
|
||||
Note that this is a dual package. The impetus for it was Webpack 5 compat. (And we'd want to move to all-ESM eventually.) But CommonJS was kept for backwards compatibility until we can be certain of its removal.
|
|
@ -2,20 +2,36 @@
|
|||
"name": "fxa-auth-client",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "dist/server/packages/fxa-auth-client/server.js",
|
||||
"main": "dist/server/cjs/packages/fxa-auth-client/server.js",
|
||||
"module": "dist/server/esm/packages/fxa-auth-client/server.js",
|
||||
"exports": {
|
||||
".": "./dist/server/packages/fxa-auth-client/server.js",
|
||||
".": {
|
||||
"import": "./dist/server/esm/packages/fxa-auth-client/server.js",
|
||||
"require": "./dist/server/cjs/packages/fxa-auth-client/server.js"
|
||||
},
|
||||
"./browser": "./dist/browser/packages/fxa-auth-client/browser.js",
|
||||
"./lib/crypto": "./dist/server/packages/fxa-auth-client/lib/crypto.js",
|
||||
"./lib/hawk": "./dist/server/packages/fxa-auth-client/lib/hawk.js",
|
||||
"./lib/recoveryKey": "./dist/server/packages/fxa-auth-client/lib/recoveryKey.js",
|
||||
"./lib/utils": "./dist/server/packages/fxa-auth-client/lib/utils.js",
|
||||
"./lib/crypto": {
|
||||
"import": "./dist/server/esm/packages/fxa-auth-client/lib/crypto.js",
|
||||
"require": "./dist/server/cjs/packages/fxa-auth-client/lib/crypto.js"
|
||||
},
|
||||
"./lib/hawk": {
|
||||
"import": "./dist/server/esm/packages/fxa-auth-client/lib/hawk.js",
|
||||
"require": "./dist/server/cjs/packages/fxa-auth-client/lib/hawk.js"
|
||||
},
|
||||
"./lib/recoveryKey": {
|
||||
"import": "./dist/server/esm/packages/fxa-auth-client/lib/recoveryKey.js",
|
||||
"require": "./dist/server/cjs/packages/fxa-auth-client/lib/recoveryKey.js"
|
||||
},
|
||||
"./lib/utils": {
|
||||
"import": "./dist/server/esm/packages/fxa-auth-client/lib/utils.js",
|
||||
"require": "./dist/server/cjs/packages/fxa-auth-client/lib/utils.js"
|
||||
},
|
||||
"./lib/": "./lib/"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext .ts",
|
||||
"postinstall": "(tsc --build tsconfig.browser.json && tsc --build) || true",
|
||||
"build": "tsc --build tsconfig.browser.json && tsc --build",
|
||||
"build": "tsc --build tsconfig.browser.json && tsc --build && tsc --build tsconfig.cjs.json",
|
||||
"compile": "tsc --noEmit",
|
||||
"ts-check": "tsc --noEmit",
|
||||
"test": "mocha -r esbuild-register test/*",
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"types": ["mocha", "./lib/types"]
|
||||
},
|
||||
"include": ["./lib/**/*", "./server.ts"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "./tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"outDir": "./dist/server/cjs",
|
||||
},
|
||||
}
|
|
@ -1,11 +1,6 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"extends": "./tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"composite": true,
|
||||
"outDir": "./dist/server",
|
||||
"types": ["mocha", "./lib/types"]
|
||||
"outDir": "./dist/server/esm",
|
||||
},
|
||||
"include": ["./lib/**/*", "./server.ts"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"sourceType": "unambiguous",
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"chrome": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"@babel/preset-typescript",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": []
|
||||
}
|
|
@ -7,9 +7,18 @@ module.exports = {
|
|||
'../lib/senders/emails/**/*.stories.tsx',
|
||||
'../lib/senders/emails/**/*.stories.ts',
|
||||
],
|
||||
staticDirs: process.env.STORYBOOK_BUILD !== 'true' ? ['..'] : undefined,
|
||||
addons: [
|
||||
'@storybook/addon-docs',
|
||||
'@storybook/addon-controls',
|
||||
'@storybook/addon-toolbars',
|
||||
],
|
||||
core: {
|
||||
builder: 'webpack5',
|
||||
},
|
||||
framework: {
|
||||
name: '@storybook/html-webpack5',
|
||||
options: {},
|
||||
},
|
||||
features: { storyStoreV7: false },
|
||||
};
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
"audit-orphaned-stripe-accounts": "CONFIG_FILES='config/secrets.json' node -r esbuild-register ./scripts/audit-orphaned-customers.ts",
|
||||
"remove-unverified-accounts": "CONFIG_FILES='config/secrets.json' node -r esbuild-register ./scripts/remove-unverified-accounts.ts",
|
||||
"emails-scss": "node -r esbuild-register ./lib/senders/emails/sass-compile-files.ts",
|
||||
"storybook": "yarn l10n-prime && yarn install-ejs && yarn emails-scss && NODE_OPTIONS=--openssl-legacy-provider start-storybook -p 6010 --no-version-updates -s ./",
|
||||
"build-storybook": "yarn l10n-prime && yarn install-ejs && yarn emails-scss && NODE_OPTIONS=--openssl-legacy-provider build-storybook && yarn build-storybook-copy-locales && yarn build-storybook-copy-templates",
|
||||
"storybook": "yarn l10n-prime && yarn install-ejs && yarn emails-scss && NODE_OPTIONS=--openssl-legacy-provider storybook dev -p 6010 --no-version-updates ",
|
||||
"build-storybook": "yarn l10n-prime && yarn install-ejs && yarn emails-scss && NODE_OPTIONS=--openssl-legacy-provider STORYBOOK_BUILD=true storybook build && yarn build-storybook-copy-locales && yarn build-storybook-copy-templates",
|
||||
"build-storybook-copy-locales": "mkdir -p ./storybook-static/public/locales && cp -R ./public/locales ./storybook-static/public",
|
||||
"build-storybook-copy-templates": "mkdir -p ./storybook-static/lib/senders/emails/templates && cp -R ./lib/senders/emails ./storybook-static/lib/senders",
|
||||
"install-ejs": "./scripts/install-ejs.sh",
|
||||
|
@ -141,12 +141,17 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@storybook/addon-controls": "^6.5.9",
|
||||
"@storybook/addon-docs": "^6.5.10",
|
||||
"@storybook/addon-toolbars": "^6.3.12",
|
||||
"@storybook/html": "^6.5.10",
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@babel/preset-react": "^7.22.5",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@storybook/addon-controls": "^7.0.23",
|
||||
"@storybook/addon-docs": "^7.0.23",
|
||||
"@storybook/addon-toolbars": "^7.0.23",
|
||||
"@storybook/html": "^7.0.23",
|
||||
"@storybook/html-webpack5": "^7.0.23",
|
||||
"@types/async-retry": "^1",
|
||||
"@types/babel__core": "7.1.14",
|
||||
"@types/babel__preset-env": "^7",
|
||||
"@types/chai": "^4.2.18",
|
||||
"@types/chai-as-promised": "^7",
|
||||
"@types/dedent": "^0",
|
||||
|
@ -163,6 +168,8 @@
|
|||
"@types/node": "^18.14.2",
|
||||
"@types/node-zendesk": "^2.0.2",
|
||||
"@types/nodemailer": "^6.4.2",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@types/request": "2.48.5",
|
||||
"@types/safe-regex": "1.1.2",
|
||||
"@types/sass": "^1",
|
||||
|
@ -172,7 +179,7 @@
|
|||
"acorn": "^8.8.0",
|
||||
"async-retry": "^1.3.3",
|
||||
"audit-filter": "^0.5.0",
|
||||
"babel-loader": "^8.3.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"binary-split": "1.0.5",
|
||||
"chai": "^4.3.6",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
|
@ -205,16 +212,19 @@
|
|||
"pm2": "^5.3.0",
|
||||
"prettier": "^2.3.1",
|
||||
"proxyquire": "^2.1.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"read": "2.1.0",
|
||||
"rimraf": "^5.0.0",
|
||||
"sass": "^1.59.2",
|
||||
"simplesmtp": "0.3.35",
|
||||
"sinon": "^9.0.3",
|
||||
"storybook": "^7.0.23",
|
||||
"through": "2.3.8",
|
||||
"type-fest": "^3.12.0",
|
||||
"typesafe-node-firestore": "^1.4.1",
|
||||
"typescript": "^4.9.3",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack": "^5.84.1",
|
||||
"webpack-watch-files-plugin": "^1.2.1",
|
||||
"ws": "^8.11.0"
|
||||
},
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
"@sentry/node": "^6.19.1",
|
||||
"asmcrypto.js": "^0.22.0",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"babel-loader": "^8.3.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"backbone": "^1.4.1",
|
||||
"backbone.cocktail": "0.5.15",
|
||||
"base32-decode": "1.0.0",
|
||||
|
|
|
@ -34,6 +34,8 @@ module.exports = function (config) {
|
|||
config.get('pairing.server_base_uri')
|
||||
);
|
||||
const PAIRING_SERVER_HTTP = PAIRING_SERVER_WEBSOCKET.replace(/^ws/, 'http');
|
||||
// We need this for Webpack 5
|
||||
const WEBPACK_DEV_SERVER = 'ws://localhost:3000';
|
||||
const SENTRY_SERVER = 'https://*.sentry.io';
|
||||
const GOOGLE_AUTH = 'https://accounts.google.com';
|
||||
const APPLE_AUTH = 'https://appleid.apple.com';
|
||||
|
@ -69,6 +71,7 @@ module.exports = function (config) {
|
|||
const styleSrc = addCdnRuleIfRequired([SELF]);
|
||||
if (config.get('env') === 'development') {
|
||||
connectSrc.push(config.get('public_url').replace(/^http/, 'ws'));
|
||||
connectSrc.push(WEBPACK_DEV_SERVER);
|
||||
scriptSrc.push("'unsafe-inline'");
|
||||
styleSrc.push("'unsafe-inline'");
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ suite.tests['blockingRules'] = function () {
|
|||
assert.isFalse(reportOnly);
|
||||
|
||||
const connectSrc = directives.connectSrc;
|
||||
assert.lengthOf(connectSrc, config.get('env') === 'development' ? 10 : 9);
|
||||
assert.lengthOf(connectSrc, config.get('env') === 'development' ? 11 : 10);
|
||||
assert.include(connectSrc, Sources.AUTH_SERVER);
|
||||
assert.include(connectSrc, Sources.GLEAN_SERVER);
|
||||
assert.include(connectSrc, Sources.GQL_SERVER);
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const {
|
||||
permitAdditionalJSImports,
|
||||
} = require('fxa-react/configs/rescripts');
|
||||
const { permitAdditionalJSImports } = require('fxa-react/configs/rescripts');
|
||||
|
||||
module.exports = [
|
||||
permitAdditionalJSImports,
|
||||
];
|
||||
module.exports = [permitAdditionalJSImports];
|
||||
|
|
|
@ -5,17 +5,19 @@
|
|||
module.exports = {
|
||||
stories: ['../src/**/*.stories.tsx'],
|
||||
staticDirs: ['../public'],
|
||||
core: {
|
||||
builder: 'webpack5',
|
||||
},
|
||||
addons: [
|
||||
'@storybook/preset-create-react-app',
|
||||
'@storybook/addon-styling',
|
||||
{
|
||||
name: '@storybook/addon-postcss',
|
||||
options: {
|
||||
postcssLoaderOptions: {
|
||||
implementation: require('postcss'),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'storybook-addon-mock/register',
|
||||
name: 'storybook-addon-mock',
|
||||
},
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-webpack5',
|
||||
options: {},
|
||||
},
|
||||
features: { storyStoreV7: false },
|
||||
};
|
||||
|
|
|
@ -2,4 +2,48 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
module.exports = require('fxa-react/configs/storybooks').customizeWebpackConfig;
|
||||
const path = require('path');
|
||||
const customizeWebpackConfig =
|
||||
require('fxa-react/configs/storybooks').customizeWebpackConfig;
|
||||
|
||||
const webpack5Fallbacks = {
|
||||
stream: false,
|
||||
timers: false,
|
||||
http: false,
|
||||
https: false,
|
||||
zlib: false,
|
||||
};
|
||||
|
||||
const includeSrcForSvgs = ({ config }) => {
|
||||
const customizedConfig = customizeWebpackConfig({ config });
|
||||
|
||||
return {
|
||||
...customizedConfig,
|
||||
resolve: {
|
||||
...customizedConfig.resolve,
|
||||
fallback: {
|
||||
...(customizedConfig.resolve.fallback || {}),
|
||||
...webpack5Fallbacks,
|
||||
},
|
||||
},
|
||||
module: {
|
||||
...customizedConfig.module,
|
||||
rules: [
|
||||
{
|
||||
oneOf: customizedConfig.module.rules[0]['oneOf'].map((x) => {
|
||||
if (x.test && x.test.test && x.test.test('.scss')) {
|
||||
return {
|
||||
...x,
|
||||
include: [path.resolve('../src')],
|
||||
};
|
||||
}
|
||||
|
||||
return x;
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = includeSrcForSvgs;
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
"test-unit": "yarn build && yarn merge-ftl-test && JEST_JUNIT_OUTPUT_FILE=../../artifacts/tests/$npm_package_name/jest-unit.xml jest --coverage --runInBand --logHeapUsage --verbose --config server/jest.config.js --forceExit -t '^(?!.*?#integration).*' --ci --reporters=default --reporters=jest-junit",
|
||||
"test-integration": "yarn build && yarn merge-ftl-test && JEST_JUNIT_OUTPUT_FILE=../../artifacts/tests/$npm_package_name/jest-integration.xml SKIP_PREFLIGHT_CHECK=true PUBLIC_URL=/ INLINE_RUNTIME_CHUNK=false rescripts test --watchAll=false --ci --reporters=default --reporters=jest-junit",
|
||||
"format": "prettier --write --config ../../_dev/.prettierrc '**'",
|
||||
"storybook": "NODE_OPTIONS=--openssl-legacy-provider start-storybook -p 6006",
|
||||
"build-storybook": "yarn merge-ftl && NODE_ENV=production yarn build-css && NODE_OPTIONS=--openssl-legacy-provider build-storybook && cp -r public/images storybook-static/ && cp -r public/locales ./storybook-static/locales",
|
||||
"storybook": "NODE_OPTIONS=--openssl-legacy-provider storybook dev -p 6006",
|
||||
"build-storybook": "yarn merge-ftl && NODE_ENV=production yarn build-css && NODE_OPTIONS=--openssl-legacy-provider storybook build && cp -r public/images storybook-static/ && cp -r public/locales ./storybook-static/locales",
|
||||
"merge-ftl": "yarn l10n-prime && grunt merge-ftl && yarn l10n-bundle",
|
||||
"merge-ftl-test": "yarn l10n-prime && grunt merge-ftl:test",
|
||||
"watch-ftl": "grunt watch-ftl"
|
||||
|
@ -51,19 +51,25 @@
|
|||
},
|
||||
"homepage": "https://github.com/mozilla/fxa/tree/main/packages/fxa-payments-server#README.md",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/core": "^7.22.5",
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@babel/preset-react": "^7.22.5",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@fluent/bundle": "^0.18.0",
|
||||
"@fluent/langneg": "^0.6.2",
|
||||
"@fluent/react": "^0.13.1",
|
||||
"@fluent/react": "^0.14.1",
|
||||
"@rescripts/cli": "~0.0.16",
|
||||
"@storybook/addon-actions": "^6.5.9",
|
||||
"@storybook/addon-links": "^6.5.9",
|
||||
"@storybook/addon-postcss": "^2.0.0",
|
||||
"@storybook/addons": "^6.5.9",
|
||||
"@storybook/react": "^6.5.9",
|
||||
"@storybook/addon-actions": "^7.0.23",
|
||||
"@storybook/addon-links": "^7.0.23",
|
||||
"@storybook/addon-styling": "^1.3.0",
|
||||
"@storybook/addons": "^7.0.23",
|
||||
"@storybook/preset-create-react-app": "^7.0.23",
|
||||
"@storybook/react": "^7.0.23",
|
||||
"@storybook/react-webpack5": "^7.0.23",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^12.1.5",
|
||||
"@types/accept-language-parser": "^1.5.1",
|
||||
"@types/babel__preset-env": "^7",
|
||||
"@types/classnames": "^2.3.1",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/jsdom": "^16.2.11",
|
||||
|
@ -78,7 +84,6 @@
|
|||
"@types/sinon": "10.0.1",
|
||||
"@types/storybook__addon-actions": "^5.2.1",
|
||||
"@types/storybook__addon-links": "^5.2.1",
|
||||
"@types/storybook__react": "^5.2.1",
|
||||
"@types/superagent": "^4.1.11",
|
||||
"@types/uuid": "^7.0.2",
|
||||
"@types/webpack": "5.28.0",
|
||||
|
@ -87,6 +92,7 @@
|
|||
"audit-filter": "^0.5.0",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"browserslist": "^4.21.4",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-react-app": "^6.0.0",
|
||||
|
@ -108,13 +114,14 @@
|
|||
"prettier": "^2.3.1",
|
||||
"redux-devtools-extension": "^2.13.9",
|
||||
"sinon": "^9.0.3",
|
||||
"storybook-addon-mock": "2.4.1",
|
||||
"storybook": "^7.0.23",
|
||||
"storybook-addon-mock": "4.0.0",
|
||||
"supertest": "^6.3.0",
|
||||
"tailwindcss": "^3.3.1",
|
||||
"ts-jest": "^29.1.0",
|
||||
"typescript": "^4.9.3",
|
||||
"wait-for-expect": "^3.0.2",
|
||||
"webpack": "^4.43.0"
|
||||
"webpack": "^5.84.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/browser": "^6.19.7",
|
||||
|
@ -150,7 +157,7 @@
|
|||
"react-dom": "^16.12.0",
|
||||
"react-redux": "^8.0.2",
|
||||
"react-router-dom": "^6.9.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-scripts": "^5.0.1",
|
||||
"react-stripe-elements": "^6.1.2",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"react-transition-group": "^4.4.2",
|
||||
|
|
|
@ -43,8 +43,13 @@ module.exports = function (config) {
|
|||
// CSP directives required for GA
|
||||
// https://developers.google.com/tag-platform/tag-manager/csp#google_analytics_4_google_analytics
|
||||
const GA_SCRIPT_SRC = 'https://*.googletagmanager.com';
|
||||
const GA_IMG_SRC = 'https://*.google-analytics.com https://*.googletagmanager.com';
|
||||
const GA_CONNECT_SRC = 'https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com';
|
||||
const GA_IMG_SRC =
|
||||
'https://*.google-analytics.com https://*.googletagmanager.com';
|
||||
const GA_CONNECT_SRC =
|
||||
'https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com';
|
||||
|
||||
// We need this for Webpack 5
|
||||
const WEBPACK_DEV_SERVER = 'ws://localhost:3032';
|
||||
|
||||
//
|
||||
// Double quoted values
|
||||
|
@ -100,7 +105,7 @@ module.exports = function (config) {
|
|||
scriptSrc: addCdnRuleIfRequired([
|
||||
SELF,
|
||||
STRIPE_SCRIPT_URL,
|
||||
PAYPAL_SCRIPT_URL
|
||||
PAYPAL_SCRIPT_URL,
|
||||
]),
|
||||
styleSrc: addCdnRuleIfRequired([SELF, UNSAFE_INLINE]),
|
||||
},
|
||||
|
@ -131,6 +136,7 @@ module.exports = function (config) {
|
|||
|
||||
if (config.get('env') === 'development') {
|
||||
rules.directives.connectSrc.push(HOT_RELOAD_WEBSOCKET);
|
||||
rules.directives.connectSrc.push(WEBPACK_DEV_SERVER);
|
||||
}
|
||||
|
||||
// If GA is enabled, add directives
|
||||
|
@ -141,8 +147,8 @@ module.exports = function (config) {
|
|||
Object.assign(rules.Sources, {
|
||||
GA_CONNECT_SRC,
|
||||
GA_IMG_SRC,
|
||||
GA_SCRIPT_SRC
|
||||
})
|
||||
GA_SCRIPT_SRC,
|
||||
});
|
||||
}
|
||||
|
||||
return rules;
|
||||
|
|
|
@ -100,11 +100,11 @@ export const App = ({
|
|||
|
||||
return (
|
||||
<AppContext.Provider value={appContextValue}>
|
||||
<Head />
|
||||
<AppLocalizationProvider
|
||||
userLocales={navigatorLanguages}
|
||||
bundles={['payments', 'react']}
|
||||
>
|
||||
<Head />
|
||||
<Localized id="document" attrs={{ title: true }}>
|
||||
<AppErrorBoundary>
|
||||
<StripeProvider apiKey={config.stripe.apiKey}>
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { AlertBar } from './index';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
it('renders as expected', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AlertBar
|
||||
dataTestId="children"
|
||||
headerId="alert-bar-header"
|
||||
|
@ -25,7 +26,7 @@ it('renders as expected', () => {
|
|||
});
|
||||
|
||||
it('renders success alert', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AlertBar
|
||||
className="alert-success"
|
||||
dataTestId="children"
|
||||
|
@ -42,7 +43,7 @@ it('renders success alert', () => {
|
|||
});
|
||||
|
||||
it('renders error alert', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AlertBar
|
||||
className="alert-error"
|
||||
dataTestId="children"
|
||||
|
@ -57,7 +58,7 @@ it('renders error alert', () => {
|
|||
});
|
||||
|
||||
it('renders newsletter error alert', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AlertBar
|
||||
className="alert-newsletter-error"
|
||||
dataTestId="children"
|
||||
|
@ -72,7 +73,7 @@ it('renders newsletter error alert', () => {
|
|||
});
|
||||
|
||||
it('renders pending alert', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AlertBar
|
||||
className="alert-pending"
|
||||
dataTestId="children"
|
||||
|
|
|
@ -8,6 +8,7 @@ import AppLayout, { SignInLayout, SettingsLayout } from './index';
|
|||
import TermsAndPrivacy from '../TermsAndPrivacy';
|
||||
import { SELECTED_PLAN } from '../../lib/mock-data';
|
||||
import { RawMetadata } from 'fxa-shared/subscriptions/types';
|
||||
import AppLocalizationProvider from 'fxa-react/lib/AppLocalizationProvider';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
|
@ -22,11 +23,13 @@ describe('AppLayout', () => {
|
|||
const subject = () => {
|
||||
return render(
|
||||
<AppContext.Provider value={defaultAppContext}>
|
||||
<AppLayout>
|
||||
<div data-testid="children">
|
||||
<TermsAndPrivacy plan={SELECTED_PLAN} />
|
||||
</div>
|
||||
</AppLayout>
|
||||
<AppLocalizationProvider messages={{ en: ['testo: lol'] }}>
|
||||
<AppLayout>
|
||||
<div data-testid="children">
|
||||
<TermsAndPrivacy plan={SELECTED_PLAN} />
|
||||
</div>
|
||||
</AppLayout>
|
||||
</AppLocalizationProvider>
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
|
@ -80,9 +83,11 @@ describe('SettingsLayout', () => {
|
|||
|
||||
return render(
|
||||
<AppContext.Provider value={appContextValue}>
|
||||
<SettingsLayout>
|
||||
<div data-testid="children">Testing</div>
|
||||
</SettingsLayout>
|
||||
<AppLocalizationProvider messages={{ en: ['testo: lol'] }}>
|
||||
<SettingsLayout>
|
||||
<div data-testid="children">Testing</div>
|
||||
</SettingsLayout>
|
||||
</AppLocalizationProvider>
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
import {
|
||||
render,
|
||||
screen,
|
||||
cleanup,
|
||||
fireEvent,
|
||||
waitFor,
|
||||
} from '@testing-library/react';
|
||||
import { screen, cleanup, fireEvent, waitFor } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { CouponForm, checkPromotionCode } from './index';
|
||||
import { CouponDetails } from 'fxa-shared/dto/auth/payments/coupon';
|
||||
|
@ -39,6 +33,7 @@ jest.mock('../../lib/apiClient', () => {
|
|||
|
||||
// eslint-disable-next-line import/first
|
||||
import { APIError, apiRetrieveCouponDetails } from '../../lib/apiClient';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
beforeEach(() => {
|
||||
(apiRetrieveCouponDetails as jest.Mock)
|
||||
|
@ -57,7 +52,7 @@ describe('CouponForm', () => {
|
|||
describe('CouponForm component', () => {
|
||||
it('renders as expected', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<CouponForm
|
||||
planId={SELECTED_PLAN.plan_id}
|
||||
coupon={undefined}
|
||||
|
@ -89,7 +84,7 @@ describe('CouponForm', () => {
|
|||
maximallyRedeemed: false,
|
||||
};
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<CouponForm
|
||||
planId={SELECTED_PLAN.plan_id}
|
||||
coupon={coupon}
|
||||
|
@ -113,7 +108,7 @@ describe('CouponForm', () => {
|
|||
.mockResolvedValue(COUPON_DETAILS_INVALID);
|
||||
const mockSetCoupon = jest.fn();
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<CouponForm
|
||||
planId={SELECTED_PLAN.plan_id}
|
||||
coupon={undefined}
|
||||
|
@ -171,7 +166,7 @@ describe('CouponForm', () => {
|
|||
maximallyRedeemed: false,
|
||||
};
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<CouponForm
|
||||
planId={SELECTED_PLAN.plan_id}
|
||||
coupon={coupon}
|
||||
|
@ -189,7 +184,7 @@ describe('CouponForm', () => {
|
|||
|
||||
it('has the input and buttons disabled during processing of a subscription', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<CouponForm
|
||||
planId={SELECTED_PLAN.plan_id}
|
||||
coupon={undefined}
|
||||
|
@ -218,7 +213,7 @@ describe('CouponForm', () => {
|
|||
maximallyRedeemed: false,
|
||||
};
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<CouponForm
|
||||
planId={SELECTED_PLAN.plan_id}
|
||||
coupon={coupon}
|
||||
|
@ -250,7 +245,7 @@ describe('CouponForm', () => {
|
|||
.mockResolvedValue(coupon);
|
||||
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<AppContext.Provider
|
||||
value={{
|
||||
...defaultAppContext,
|
||||
|
@ -284,7 +279,7 @@ describe('CouponForm', () => {
|
|||
.mockResolvedValue(COUPON_DETAILS_INVALID);
|
||||
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<AppContext.Provider
|
||||
value={{
|
||||
...defaultAppContext,
|
||||
|
|
|
@ -3,31 +3,40 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render, cleanup, fireEvent } from '@testing-library/react';
|
||||
import { cleanup, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { DialogMessage } from './index';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
it('renders as expected', () => {
|
||||
const onDismiss = jest.fn();
|
||||
const ariaLabelledBy = "message-header";
|
||||
const ariaDescribedBy = "message-description";
|
||||
const { queryByTestId } = render(
|
||||
const ariaLabelledBy = 'message-header';
|
||||
const ariaDescribedBy = 'message-description';
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<DialogMessage
|
||||
onDismiss={onDismiss}
|
||||
headerId={ariaLabelledBy}
|
||||
descId={ariaDescribedBy}
|
||||
>
|
||||
<div id={ariaLabelledBy} data-testid="children">Message for Mom</div>
|
||||
<div id={ariaLabelledBy} data-testid="children">
|
||||
Message for Mom
|
||||
</div>
|
||||
<p id={ariaDescribedBy}>Hi mom</p>
|
||||
</DialogMessage>
|
||||
);
|
||||
expect(queryByTestId('dialog-message-container')).toHaveClass('blocker');
|
||||
expect(queryByTestId('children')).toBeInTheDocument();
|
||||
expect(queryByTestId('dialog-message-information')).toHaveAttribute('aria-labelledby', ariaLabelledBy);
|
||||
expect(queryByTestId('dialog-message-information')).toHaveAttribute('aria-describedby', ariaDescribedBy);
|
||||
expect(queryByTestId('dialog-message-information')).toHaveAttribute(
|
||||
'aria-labelledby',
|
||||
ariaLabelledBy
|
||||
);
|
||||
expect(queryByTestId('dialog-message-information')).toHaveAttribute(
|
||||
'aria-describedby',
|
||||
ariaDescribedBy
|
||||
);
|
||||
expect(queryByTestId('dialog-message-information')).toHaveAttribute(
|
||||
'role',
|
||||
'dialog'
|
||||
|
@ -36,16 +45,18 @@ it('renders as expected', () => {
|
|||
|
||||
it('accepts an alternate className', () => {
|
||||
const onDismiss = jest.fn();
|
||||
const ariaLabelledBy = "barquux-message-header";
|
||||
const ariaDescribedBy = "barquux-message-description";
|
||||
const { queryByTestId } = render(
|
||||
const ariaLabelledBy = 'barquux-message-header';
|
||||
const ariaDescribedBy = 'barquux-message-description';
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<DialogMessage
|
||||
onDismiss={onDismiss}
|
||||
className="barquux"
|
||||
headerId={ariaLabelledBy}
|
||||
descId={ariaDescribedBy}
|
||||
>
|
||||
<div id={ariaLabelledBy} data-testid="children">Message for Mom</div>
|
||||
<div id={ariaLabelledBy} data-testid="children">
|
||||
Message for Mom
|
||||
</div>
|
||||
<p id={ariaDescribedBy}>Hi mom</p>
|
||||
</DialogMessage>
|
||||
);
|
||||
|
@ -54,15 +65,17 @@ it('accepts an alternate className', () => {
|
|||
|
||||
it('calls onDismiss on click outside', () => {
|
||||
const onDismiss = jest.fn();
|
||||
const ariaLabelledBy = "dismiss-message-header";
|
||||
const ariaDescribedBy = "dismiss-message-description";
|
||||
const { container, getByTestId } = render(
|
||||
const ariaLabelledBy = 'dismiss-message-header';
|
||||
const ariaDescribedBy = 'dismiss-message-description';
|
||||
const { container, getByTestId } = renderWithLocalizationProvider(
|
||||
<DialogMessage
|
||||
onDismiss={onDismiss}
|
||||
headerId={ariaLabelledBy}
|
||||
descId={ariaDescribedBy}
|
||||
>
|
||||
<div id={ariaLabelledBy} data-testid="children">Message for Mom</div>
|
||||
<div id={ariaLabelledBy} data-testid="children">
|
||||
Message for Mom
|
||||
</div>
|
||||
<p id={ariaDescribedBy}>Hi mom</p>
|
||||
</DialogMessage>
|
||||
);
|
||||
|
@ -73,11 +86,13 @@ it('calls onDismiss on click outside', () => {
|
|||
});
|
||||
|
||||
it('hides the close button when onDismiss is not supplied', () => {
|
||||
const ariaLabelledBy = "dismiss-header";
|
||||
const ariaDescribedBy = "dismiss-description";
|
||||
const { queryByTestId } = render(
|
||||
const ariaLabelledBy = 'dismiss-header';
|
||||
const ariaDescribedBy = 'dismiss-description';
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<DialogMessage headerId={ariaLabelledBy} descId={ariaDescribedBy}>
|
||||
<div id={ariaLabelledBy} data-testid="children">Message for Mom</div>
|
||||
<div id={ariaLabelledBy} data-testid="children">
|
||||
Message for Mom
|
||||
</div>
|
||||
<p id={ariaDescribedBy}>Hi mom</p>
|
||||
</DialogMessage>
|
||||
);
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import Header from './index';
|
||||
import { Profile } from '../../store/types';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
let userProfile: Profile = {
|
||||
avatar: './avatar.svg',
|
||||
|
@ -26,7 +27,9 @@ afterEach(cleanup);
|
|||
describe('Header', () => {
|
||||
it('renders as expected', () => {
|
||||
const subject = () => {
|
||||
return render(<Header {...{ profile: userProfile }} />);
|
||||
return renderWithLocalizationProvider(
|
||||
<Header {...{ profile: userProfile }} />
|
||||
);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
@ -35,10 +38,10 @@ describe('Header', () => {
|
|||
expect(avatar).toHaveAttribute('alt', userProfile.displayName);
|
||||
});
|
||||
|
||||
it('renders without profile', () => {
|
||||
it('renderWithLocalizationProviders without profile', () => {
|
||||
userProfile.displayName = null;
|
||||
const subject = () => {
|
||||
return render(<Header />);
|
||||
return renderWithLocalizationProvider(<Header />);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
@ -50,7 +53,9 @@ describe('Header', () => {
|
|||
it('alt falls back to email is displayName is null', () => {
|
||||
userProfile.displayName = null;
|
||||
const subject = () => {
|
||||
return render(<Header {...{ profile: userProfile }} />);
|
||||
return renderWithLocalizationProvider(
|
||||
<Header {...{ profile: userProfile }} />
|
||||
);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { LoadingOverlay } from './index';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
it('renders as null isLoading=false', () => {
|
||||
const { queryByTestId } = render(<LoadingOverlay isLoading={false} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<LoadingOverlay isLoading={false} />
|
||||
);
|
||||
const result = queryByTestId('loading-overlay');
|
||||
expect(result).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders as expected when isLoading=true', () => {
|
||||
const { queryByTestId } = render(<LoadingOverlay isLoading={true} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<LoadingOverlay isLoading={true} />
|
||||
);
|
||||
const result = queryByTestId('loading-overlay');
|
||||
expect(result).toBeInTheDocument();
|
||||
});
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { LoadingSpinner } from './index';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
it('renders as expected', () => {
|
||||
const { queryByTestId } = render(<LoadingSpinner />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(<LoadingSpinner />);
|
||||
const result = queryByTestId('loading-spinner');
|
||||
expect(result).toBeInTheDocument();
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState } from 'react';
|
||||
import { fireEvent, render, waitFor } from '@testing-library/react';
|
||||
import { fireEvent, waitFor } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { apiFetchAccountStatus } from '../../lib/apiClient';
|
||||
import {
|
||||
|
@ -9,6 +9,7 @@ import {
|
|||
} from './index';
|
||||
import { Localized } from '@fluent/react';
|
||||
import { CheckoutType } from 'fxa-shared/subscriptions/types';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
jest.mock('../../lib/apiClient', () => ({
|
||||
apiFetchAccountStatus: jest.fn(),
|
||||
|
@ -75,7 +76,7 @@ const WrapNewUserEmailForm = ({
|
|||
describe('NewUserEmailForm test', () => {
|
||||
it('renders as expected', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<WrapNewUserEmailForm
|
||||
accountExistsReturnValue={false}
|
||||
invalidDomain={false}
|
||||
|
@ -110,7 +111,7 @@ describe('NewUserEmailForm test', () => {
|
|||
|
||||
it('renders as expected, with metadata configuration', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<WrapNewUserEmailForm
|
||||
accountExistsReturnValue={false}
|
||||
invalidDomain={false}
|
||||
|
@ -135,7 +136,7 @@ describe('NewUserEmailForm test', () => {
|
|||
|
||||
it('shows error when invalid email is input to first field', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<WrapNewUserEmailForm
|
||||
accountExistsReturnValue={false}
|
||||
invalidDomain={false}
|
||||
|
@ -156,7 +157,7 @@ describe('NewUserEmailForm test', () => {
|
|||
|
||||
it('shows no error when valid email is input to first field', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<WrapNewUserEmailForm
|
||||
accountExistsReturnValue={false}
|
||||
invalidDomain={false}
|
||||
|
@ -176,7 +177,7 @@ describe('NewUserEmailForm test', () => {
|
|||
|
||||
it('shows no error when empty string is provided to second field', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<WrapNewUserEmailForm
|
||||
accountExistsReturnValue={false}
|
||||
invalidDomain={false}
|
||||
|
@ -200,7 +201,7 @@ describe('NewUserEmailForm test', () => {
|
|||
|
||||
it('shows error when emails do not match', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<WrapNewUserEmailForm
|
||||
accountExistsReturnValue={false}
|
||||
invalidDomain={false}
|
||||
|
@ -225,7 +226,7 @@ describe('NewUserEmailForm test', () => {
|
|||
|
||||
it('shows no error when emails match', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<WrapNewUserEmailForm
|
||||
accountExistsReturnValue={false}
|
||||
invalidDomain={false}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { PaypalButton, PaypalButtonProps } from './index';
|
||||
|
||||
import { PickPartial } from '../../lib/types';
|
||||
import { CUSTOMER, PLAN } from '../../lib/mock-data';
|
||||
import { CheckoutType } from 'fxa-shared/subscriptions/types';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
const Subject = ({
|
||||
disabled = false,
|
||||
|
@ -52,7 +53,9 @@ describe('PaypalButton', () => {
|
|||
it("Doesn't render the PayPal button if the PayPal script fails to load", async () => {
|
||||
// The script is loaded in this button's consumer (e.g. SubscriptionCreate), so we
|
||||
// can guarantee that it won't be loaded for the button in isolation
|
||||
render(<Subject checkoutType={CheckoutType.WITH_ACCOUNT} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject checkoutType={CheckoutType.WITH_ACCOUNT} />
|
||||
);
|
||||
expect(screen.queryByTestId('paypal-button')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import TestRenderer from 'react-test-renderer';
|
||||
|
||||
|
@ -9,7 +9,12 @@ import {
|
|||
getLocalizedDateString,
|
||||
} from '../../lib/formats';
|
||||
import { Customer, Plan } from '../../store/types';
|
||||
import { MOCK_PLANS, getLocalizedMessage } from '../../lib/test-utils';
|
||||
import {
|
||||
MOCK_PLANS,
|
||||
getLocalizedMessage,
|
||||
renderWithLocalizationProvider,
|
||||
withLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
import { getFtlBundle } from 'fxa-react/lib/test-utils';
|
||||
import { FluentBundle } from '@fluent/bundle';
|
||||
import AppContext, { defaultAppContext } from '../../lib/AppContext';
|
||||
|
@ -109,7 +114,7 @@ afterEach(() => {
|
|||
describe('PaymentConfirmation', () => {
|
||||
it('renders as expected', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PaymentConfirmation
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -137,7 +142,7 @@ describe('PaymentConfirmation', () => {
|
|||
|
||||
it('renders as expected with no display name', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PaymentConfirmation
|
||||
{...{
|
||||
profile: userProfileNoDisplayName,
|
||||
|
@ -160,7 +165,7 @@ describe('PaymentConfirmation', () => {
|
|||
|
||||
it('renders as expected with custom success button label text', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PaymentConfirmation
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -189,7 +194,7 @@ describe('PaymentConfirmation', () => {
|
|||
|
||||
it('renders as expected with custom success button label text localized to xx-pirate', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<AppContext.Provider
|
||||
value={{ ...defaultAppContext, navigatorLanguages: ['xx-pirate'] }}
|
||||
>
|
||||
|
@ -227,7 +232,7 @@ describe('PaymentConfirmation', () => {
|
|||
},
|
||||
});
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PaymentConfirmation
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -260,7 +265,7 @@ describe('PaymentConfirmation', () => {
|
|||
},
|
||||
});
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<AppContext.Provider
|
||||
value={{ ...defaultAppContext, navigatorLanguages: ['fy-NL'] }}
|
||||
>
|
||||
|
@ -292,7 +297,7 @@ describe('PaymentConfirmation', () => {
|
|||
|
||||
it('renders with the invoice total amount when an invoice is present', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={{ ...defaultAppContext }}>
|
||||
<PaymentConfirmation
|
||||
{...{
|
||||
|
@ -314,7 +319,7 @@ describe('PaymentConfirmation', () => {
|
|||
|
||||
it('renders without Order details if not available', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PaymentConfirmation
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -335,7 +340,7 @@ describe('PaymentConfirmation', () => {
|
|||
|
||||
describe('When payment_provider is "paypal"', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PaymentConfirmation
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -362,7 +367,7 @@ describe('PaymentConfirmation', () => {
|
|||
|
||||
describe('When payment_provider is "stripe"', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PaymentConfirmation
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -413,7 +418,7 @@ describe('PaymentConfirmation', () => {
|
|||
};
|
||||
|
||||
const testRenderer = TestRenderer.create(
|
||||
<PaymentConfirmation {...props} />
|
||||
withLocalizationProvider(<PaymentConfirmation {...props} />)
|
||||
);
|
||||
const testInstance = testRenderer.root;
|
||||
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { act, cleanup, fireEvent, render } from '@testing-library/react';
|
||||
import { act, cleanup, fireEvent } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import TestRenderer from 'react-test-renderer';
|
||||
|
||||
import { PaymentConsentCheckbox } from '.';
|
||||
import { MOCK_PLANS } from '../../lib/test-utils';
|
||||
import {
|
||||
MOCK_PLANS,
|
||||
renderWithLocalizationProvider,
|
||||
withLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
import useValidatorState from '../../lib/validator';
|
||||
import { Plan } from '../../store/types';
|
||||
import { Form } from '../fields';
|
||||
|
@ -39,7 +43,9 @@ describe('components/PaymentConsentCheckbox', () => {
|
|||
const plan_id = 'plan_daily';
|
||||
const plan = findMockPlan(plan_id);
|
||||
const props = { plan };
|
||||
const { findByTestId } = render(<WrapCheckbox {...props} />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<WrapCheckbox {...props} />
|
||||
);
|
||||
const checkbox = await findByTestId('confirm');
|
||||
|
||||
expect(checkbox).toBeVisible();
|
||||
|
@ -53,7 +59,9 @@ describe('components/PaymentConsentCheckbox', () => {
|
|||
plan,
|
||||
onClick: onClickSpy,
|
||||
};
|
||||
const { findByTestId } = render(<WrapCheckbox {...props} />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<WrapCheckbox {...props} />
|
||||
);
|
||||
const checkbox = await findByTestId('confirm');
|
||||
|
||||
await act(async () => {
|
||||
|
@ -68,7 +76,9 @@ describe('components/PaymentConsentCheckbox', () => {
|
|||
function runTests(plan: Plan, expectedMsgId: string) {
|
||||
const props = { plan };
|
||||
|
||||
const testRenderer = TestRenderer.create(<WrapCheckbox {...props} />);
|
||||
const testRenderer = TestRenderer.create(
|
||||
withLocalizationProvider(<WrapCheckbox {...props} />)
|
||||
);
|
||||
const testInstance = testRenderer.root;
|
||||
const legalCheckbox = testInstance.findByProps({ id: expectedMsgId });
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { PaymentErrorView } from './index';
|
|||
import { SELECTED_PLAN } from '../../lib/mock-data';
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||
import { Meta } from '@storybook/react';
|
||||
import AppLocalizationProvider from 'fxa-react/lib/AppLocalizationProvider';
|
||||
|
||||
export default {
|
||||
title: 'components/PaymentError',
|
||||
|
@ -11,20 +12,25 @@ export default {
|
|||
|
||||
const storyWithProps = () => {
|
||||
const story = () => (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route
|
||||
path="*"
|
||||
element={
|
||||
<PaymentErrorView
|
||||
error={{ code: 'general_paypal_error' }}
|
||||
actionFn={() => {}}
|
||||
plan={SELECTED_PLAN}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route
|
||||
path="*"
|
||||
element={
|
||||
<PaymentErrorView
|
||||
error={{ code: 'general_paypal_error' }}
|
||||
actionFn={() => {}}
|
||||
plan={SELECTED_PLAN}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</AppLocalizationProvider>
|
||||
);
|
||||
|
||||
return story;
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup, fireEvent, act } from '@testing-library/react';
|
||||
import { cleanup, fireEvent, act } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { getLocalizedMessage } from '../../lib/test-utils';
|
||||
import {
|
||||
getLocalizedMessage,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
import { getFtlBundle } from 'fxa-react/lib/test-utils';
|
||||
import { FluentBundle } from '@fluent/bundle';
|
||||
|
||||
|
@ -27,7 +30,7 @@ describe('PaymentErrorView test with l10n', () => {
|
|||
});
|
||||
|
||||
it('renders as expected', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentErrorView
|
||||
actionFn={() => {}}
|
||||
error={{ code: 'general_paypal_error' }}
|
||||
|
@ -54,7 +57,7 @@ describe('PaymentErrorView test with l10n', () => {
|
|||
|
||||
it('calls passed onRetry function when retry button clicked', async () => {
|
||||
const onRetry = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentErrorView
|
||||
actionFn={onRetry}
|
||||
error={{ code: 'general_paypal_error' }}
|
||||
|
@ -70,7 +73,7 @@ describe('PaymentErrorView test with l10n', () => {
|
|||
});
|
||||
|
||||
it('navigates to the correct relative URL when the "Manage my subscription" button is clicked', async () => {
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentErrorView
|
||||
actionFn={() => {}}
|
||||
error={{ code: 'no_subscription_change' }}
|
||||
|
@ -86,7 +89,7 @@ describe('PaymentErrorView test with l10n', () => {
|
|||
});
|
||||
|
||||
it('uses the given SubscriptionTitle', async () => {
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentErrorView
|
||||
subscriptionTitle={<SubscriptionTitle screenType={'noplanchange'} />}
|
||||
actionFn={() => {}}
|
||||
|
@ -107,7 +110,7 @@ describe('PaymentErrorView test with l10n', () => {
|
|||
});
|
||||
|
||||
it('does not render the ActionButton for post-subscription creation errors', async () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentErrorView
|
||||
actionFn={() => {}}
|
||||
error={{ code: 'fxa_fetch_profile_customer_error' }}
|
||||
|
@ -129,7 +132,7 @@ describe('PaymentErrorView test with l10n', () => {
|
|||
});
|
||||
|
||||
it('shows FxA legal links in footer when isPasswordlessCheckout is true', async () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentErrorView
|
||||
actionFn={() => {}}
|
||||
error={{ code: 'general_paypal_error' }}
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
render,
|
||||
cleanup,
|
||||
act,
|
||||
fireEvent,
|
||||
queryByTestId,
|
||||
} from '@testing-library/react';
|
||||
import { cleanup, act, fireEvent, queryByTestId } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import waitForExpect from 'wait-for-expect';
|
||||
|
||||
|
@ -16,6 +10,7 @@ import {
|
|||
mockStripeElementOnBlurFns,
|
||||
elementChangeResponse,
|
||||
MOCK_CUSTOMER,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
|
||||
import PaymentForm, { PaymentFormProps } from './index';
|
||||
|
@ -68,7 +63,8 @@ const Subject = ({
|
|||
};
|
||||
|
||||
it('renders all expected default fields and elements', () => {
|
||||
const { container, queryAllByTestId, getByTestId } = render(<Subject />);
|
||||
const { container, queryAllByTestId, getByTestId } =
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
expect(container.querySelector('button.cancel')).not.toBeInTheDocument();
|
||||
expect(container.querySelector('span.spinner')).not.toBeInTheDocument();
|
||||
|
@ -81,7 +77,7 @@ it('renders all expected default fields and elements', () => {
|
|||
});
|
||||
|
||||
it('renders error tooltips for invalid stripe elements', () => {
|
||||
const { getByTestId } = render(<Subject />);
|
||||
const { getByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
const mockErrors = {
|
||||
cardElement: 'CARD BAD',
|
||||
|
@ -109,7 +105,7 @@ it('renders error tooltips for invalid stripe elements', () => {
|
|||
});
|
||||
|
||||
const renderWithValidFields = (props?: SubjectProps) => {
|
||||
const renderResult = render(<Subject {...props} />);
|
||||
const renderResult = renderWithLocalizationProvider(<Subject {...props} />);
|
||||
const { getByTestId } = renderResult;
|
||||
|
||||
expect(getByTestId('submit')).toHaveClass('payment-button-disabled');
|
||||
|
@ -155,12 +151,14 @@ it('when confirm = true, enables submit button when all fields are valid and che
|
|||
});
|
||||
|
||||
it('omits the confirmation checkbox when confirm = false', () => {
|
||||
const { queryByTestId } = render(<Subject {...{ confirm: false }} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject {...{ confirm: false }} />
|
||||
);
|
||||
expect(queryByTestId('confirm')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('includes the confirmation checkbox when confirm = true and plan supplied', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject {...{ confirm: true, plan: SELECTED_PLAN }} />
|
||||
);
|
||||
expect(queryByTestId('confirm')).toBeInTheDocument();
|
||||
|
@ -203,25 +201,31 @@ it('renders a progress spinner when submitted, disables further submission (issu
|
|||
});
|
||||
|
||||
it('renders a progress spinner when inProgress = true', () => {
|
||||
const { queryByTestId } = render(<Subject {...{ inProgress: true }} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject {...{ inProgress: true }} />
|
||||
);
|
||||
expect(queryByTestId('loading-spinner')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders a progress spinner when inProgress = true and onCancel supplied', () => {
|
||||
const onCancel = jest.fn();
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject {...{ inProgress: true, onCancel }} />
|
||||
);
|
||||
expect(queryByTestId('loading-spinner')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('includes the cancel button when onCancel supplied', () => {
|
||||
const { queryByTestId } = render(<Subject {...{ onCancel: jest.fn() }} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject {...{ onCancel: jest.fn() }} />
|
||||
);
|
||||
expect(queryByTestId('cancel')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays an error for empty name', () => {
|
||||
const { getByText, getByTestId } = render(<Subject />);
|
||||
const { getByText, getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
fireEvent.change(getByTestId('name'), { target: { value: '123' } });
|
||||
fireEvent.change(getByTestId('name'), { target: { value: '' } });
|
||||
fireEvent.blur(getByTestId('name'));
|
||||
|
@ -269,7 +273,7 @@ it('does not call onSubmit if somehow submitted while in progress', async () =>
|
|||
|
||||
describe('with existing card', () => {
|
||||
it('renders correctly', () => {
|
||||
const { queryByTestId, queryByText } = render(
|
||||
const { queryByTestId, queryByText } = renderWithLocalizationProvider(
|
||||
<Subject customer={MOCK_CUSTOMER} plan={SELECTED_PLAN} />
|
||||
);
|
||||
expect(queryByTestId('card-logo-and-last-four')).toBeInTheDocument();
|
||||
|
@ -281,14 +285,16 @@ describe('with existing card', () => {
|
|||
|
||||
it('renders the payment form for customer without subscriptions', () => {
|
||||
const customer = { ...MOCK_CUSTOMER, subscriptions: [] };
|
||||
const { queryByTestId } = render(<Subject customer={customer} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject customer={customer} />
|
||||
);
|
||||
expect(queryByTestId('name')).toBeInTheDocument();
|
||||
expect(queryByTestId('card-details')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls the submit handler', async () => {
|
||||
const onSubmit = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customer={MOCK_CUSTOMER}
|
||||
plan={SELECTED_PLAN}
|
||||
|
@ -304,7 +310,7 @@ describe('with existing card', () => {
|
|||
|
||||
describe('with existing PayPal billing agreement', () => {
|
||||
it('renders correctly', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customer={{ ...MOCK_CUSTOMER, payment_provider: 'paypal' }}
|
||||
plan={SELECTED_PLAN}
|
||||
|
@ -316,7 +322,7 @@ describe('with existing PayPal billing agreement', () => {
|
|||
|
||||
it('calls the submit handler', async () => {
|
||||
const onSubmit = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customer={{ ...MOCK_CUSTOMER, payment_provider: 'paypal' }}
|
||||
plan={SELECTED_PLAN}
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { act, cleanup, fireEvent, render } from '@testing-library/react';
|
||||
import { act, cleanup, fireEvent } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { PaymentMethodHeader, PaymentMethodHeaderType } from '.';
|
||||
import { getLocalizedMessage, MOCK_PLANS } from '../../lib/test-utils';
|
||||
import {
|
||||
getLocalizedMessage,
|
||||
MOCK_PLANS,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
import { getFtlBundle } from 'fxa-react/lib/test-utils';
|
||||
import { FluentBundle } from '@fluent/bundle';
|
||||
|
||||
|
@ -19,7 +23,9 @@ describe('components/PaymentMethodHeader', () => {
|
|||
it('render header without prefix', async () => {
|
||||
const plan = MOCK_PLANS[0];
|
||||
const props = { plan, onClick: () => {} };
|
||||
const { queryByTestId } = render(<PaymentMethodHeader {...props} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentMethodHeader {...props} />
|
||||
);
|
||||
|
||||
expect(queryByTestId('header')).toBeInTheDocument();
|
||||
expect(queryByTestId('header-prefix')).not.toBeInTheDocument();
|
||||
|
@ -32,7 +38,9 @@ describe('components/PaymentMethodHeader', () => {
|
|||
onClick: () => {},
|
||||
type: PaymentMethodHeaderType.SecondStep,
|
||||
};
|
||||
const { queryByTestId } = render(<PaymentMethodHeader {...props} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentMethodHeader {...props} />
|
||||
);
|
||||
|
||||
expect(queryByTestId('header')).not.toBeInTheDocument();
|
||||
expect(queryByTestId('header-prefix')).toBeInTheDocument();
|
||||
|
@ -72,7 +80,9 @@ describe('components/PaymentMethodHeader', () => {
|
|||
it('Checkbox renders as expected', async () => {
|
||||
const plan = MOCK_PLANS[0];
|
||||
const props = { plan, onClick: () => {} };
|
||||
const { findByTestId } = render(<PaymentMethodHeader {...props} />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentMethodHeader {...props} />
|
||||
);
|
||||
const checkbox = await findByTestId('confirm');
|
||||
|
||||
expect(checkbox).toBeVisible();
|
||||
|
@ -82,7 +92,9 @@ describe('components/PaymentMethodHeader', () => {
|
|||
const plan = MOCK_PLANS[0];
|
||||
const onClickSpy = jest.fn();
|
||||
const props = { plan, onClick: onClickSpy };
|
||||
const { findByTestId } = render(<PaymentMethodHeader {...props} />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentMethodHeader {...props} />
|
||||
);
|
||||
const checkbox = await findByTestId('confirm');
|
||||
|
||||
await act(async () => {
|
||||
|
@ -99,7 +111,9 @@ describe('components/PaymentMethodHeader', () => {
|
|||
const expectedMsg =
|
||||
'I authorize Mozilla, maker of Firefox products, to charge my payment method for the amount shown, according to Terms of ServiceOpens in new window and Privacy NoticeOpens in new window, until I cancel my subscription.';
|
||||
|
||||
const { findByTestId } = render(<PaymentMethodHeader {...props} />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentMethodHeader {...props} />
|
||||
);
|
||||
|
||||
const checkbox = await findByTestId('confirm');
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { getLocalizedMessage } from '../../lib/test-utils';
|
||||
import {
|
||||
getLocalizedMessage,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
import { getFtlBundle } from 'fxa-react/lib/test-utils';
|
||||
import { FluentBundle } from '@fluent/bundle';
|
||||
|
||||
|
@ -15,7 +18,9 @@ describe('PaymentProcessing tests', () => {
|
|||
});
|
||||
|
||||
it('renders as expected', () => {
|
||||
const { queryByTestId } = render(<PaymentProcessing provider="paypal" />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<PaymentProcessing provider="paypal" />
|
||||
);
|
||||
|
||||
const subscriptionTitle = queryByTestId('subscription-processing-title');
|
||||
expect(subscriptionTitle).toBeInTheDocument();
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import PaymentProviderDetails from './index';
|
||||
import * as Customers from '../../lib/mock-data';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('PaymentProviderDetails', () => {
|
||||
describe('payment_method === "stripe" and an expirationDate is provided', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PaymentProviderDetails {...{ customer: Customers.CUSTOMER }} />
|
||||
);
|
||||
};
|
||||
|
@ -30,7 +31,7 @@ describe('PaymentProviderDetails', () => {
|
|||
|
||||
describe('When payment_method === "paypal"', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PaymentProviderDetails {...{ customer: Customers.PAYPAL_CUSTOMER }} />
|
||||
);
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render, cleanup, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { cleanup, fireEvent, waitFor } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import TestRenderer from 'react-test-renderer';
|
||||
|
||||
|
@ -13,7 +13,12 @@ import {
|
|||
getLocalizedCurrency,
|
||||
getLocalizedCurrencyString,
|
||||
} from '../../lib/formats';
|
||||
import { MOCK_PLANS, getLocalizedMessage } from '../../lib/test-utils';
|
||||
import {
|
||||
MOCK_PLANS,
|
||||
getLocalizedMessage,
|
||||
renderWithLocalizationProvider,
|
||||
withLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
import { getFtlBundle } from 'fxa-react/lib/test-utils';
|
||||
import { FluentBundle } from '@fluent/bundle';
|
||||
import { updateConfig } from '../../lib/config';
|
||||
|
@ -111,7 +116,7 @@ afterEach(() => {
|
|||
describe('PlanDetails', () => {
|
||||
it('renders as expected without tax', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -154,7 +159,7 @@ describe('PlanDetails', () => {
|
|||
},
|
||||
};
|
||||
const subject = () => {
|
||||
return render(<PlanDetails {...props} />);
|
||||
return renderWithLocalizationProvider(<PlanDetails {...props} />);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
@ -192,7 +197,7 @@ describe('PlanDetails', () => {
|
|||
},
|
||||
};
|
||||
const subject = () => {
|
||||
return render(<PlanDetails {...props} />);
|
||||
return renderWithLocalizationProvider(<PlanDetails {...props} />);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
@ -247,7 +252,7 @@ describe('PlanDetails', () => {
|
|||
},
|
||||
};
|
||||
const subject = () => {
|
||||
return render(<PlanDetails {...props} />);
|
||||
return renderWithLocalizationProvider(<PlanDetails {...props} />);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
@ -265,7 +270,7 @@ describe('PlanDetails', () => {
|
|||
},
|
||||
});
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -295,7 +300,7 @@ describe('PlanDetails', () => {
|
|||
},
|
||||
});
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<AppContext.Provider
|
||||
value={{ ...defaultAppContext, navigatorLanguages: ['fy-NL'] }}
|
||||
>
|
||||
|
@ -326,7 +331,7 @@ describe('PlanDetails', () => {
|
|||
});
|
||||
|
||||
it('renders product_name when product:name is not present', () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -352,7 +357,7 @@ describe('PlanDetails', () => {
|
|||
},
|
||||
};
|
||||
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -371,7 +376,7 @@ describe('PlanDetails', () => {
|
|||
|
||||
it('hides expand button when showExpandButton is false', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -393,7 +398,7 @@ describe('PlanDetails', () => {
|
|||
|
||||
it('shows and hides detail section when expand button is clicked', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -423,7 +428,7 @@ describe('PlanDetails', () => {
|
|||
|
||||
it('sets role to "complementary" when isMobile is false', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -445,7 +450,7 @@ describe('PlanDetails', () => {
|
|||
|
||||
it('does not set role to "complementary" when isMobile is true', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -464,7 +469,7 @@ describe('PlanDetails', () => {
|
|||
|
||||
it('does not show the coupon success message when there is no coupon used', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -507,7 +512,7 @@ describe('PlanDetails', () => {
|
|||
};
|
||||
|
||||
const subject = () => {
|
||||
return render(<PlanDetails {...props} />);
|
||||
return renderWithLocalizationProvider(<PlanDetails {...props} />);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
@ -535,7 +540,7 @@ describe('PlanDetails', () => {
|
|||
|
||||
it('for coupon info box without couponDurationDate, display coupon-success message', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -560,7 +565,7 @@ describe('PlanDetails', () => {
|
|||
|
||||
it('for coupon info box with couponDurationDate, display coupon-success-with-date message', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -586,7 +591,7 @@ describe('PlanDetails', () => {
|
|||
|
||||
it('do not show either coupon-success message, if info box is empty', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -609,7 +614,7 @@ describe('PlanDetails', () => {
|
|||
|
||||
it('show total for 100% coupon', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanDetails
|
||||
{...{
|
||||
profile: userProfile,
|
||||
|
@ -661,7 +666,9 @@ describe('PlanDetails', () => {
|
|||
},
|
||||
};
|
||||
|
||||
const testRenderer = TestRenderer.create(<PlanDetails {...props} />);
|
||||
const testRenderer = TestRenderer.create(
|
||||
withLocalizationProvider(<PlanDetails {...props} />)
|
||||
);
|
||||
const testInstance = testRenderer.root;
|
||||
|
||||
const planPriceComponent = testInstance.findByProps({
|
||||
|
|
|
@ -7,6 +7,7 @@ import { PlanErrorDialog } from './index';
|
|||
import { PLANS } from '../../lib/mock-data';
|
||||
import { FetchState, Plan } from '../../store/types';
|
||||
import { Meta } from '@storybook/react';
|
||||
import AppLocalizationProvider from 'fxa-react/lib/AppLocalizationProvider';
|
||||
|
||||
export default {
|
||||
title: 'components/PlanErrorDialog',
|
||||
|
@ -25,7 +26,12 @@ const storyWithContext = (
|
|||
storyName?: string
|
||||
) => {
|
||||
const story = () => (
|
||||
<PlanErrorDialog locationReload={locationReload} plans={plans} />
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<PlanErrorDialog locationReload={locationReload} plans={plans} />
|
||||
</AppLocalizationProvider>
|
||||
);
|
||||
|
||||
if (storyName) story.storyName = storyName;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import PlanErrorDialog from './index';
|
||||
import { PLANS } from '../../lib/mock-data';
|
||||
import { FetchState, Plan } from '../../store/types';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
const locationReload = () => {};
|
||||
const plans: FetchState<Plan[], any> = {
|
||||
|
@ -18,7 +19,7 @@ afterEach(cleanup);
|
|||
describe('PlanErrorDialog', () => {
|
||||
it('renders as expected for no plan for product', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanErrorDialog
|
||||
{...{
|
||||
locationReload,
|
||||
|
@ -34,7 +35,7 @@ describe('PlanErrorDialog', () => {
|
|||
|
||||
it('renders as expected for no selectedPlan', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PlanErrorDialog
|
||||
{...{
|
||||
locationReload,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { PriceDetails } from '.';
|
||||
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
const defaultPriceDetailsProps = {
|
||||
total: 2000,
|
||||
|
@ -12,7 +12,9 @@ describe('PriceDetails', () => {
|
|||
describe('PriceDetails component', () => {
|
||||
it('renders NoInterval component', () => {
|
||||
const subject = () => {
|
||||
return render(<PriceDetails {...defaultPriceDetailsProps} />);
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails {...defaultPriceDetailsProps} />
|
||||
);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
@ -21,7 +23,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders Interval component', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'month'}
|
||||
|
@ -40,7 +42,9 @@ describe('PriceDetails', () => {
|
|||
describe('NoInterval', () => {
|
||||
it('renders without tax', () => {
|
||||
const subject = () => {
|
||||
return render(<PriceDetails {...defaultPriceDetailsProps} />);
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails {...defaultPriceDetailsProps} />
|
||||
);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
@ -50,7 +54,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders with tax with showTax set', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
tax={300}
|
||||
|
@ -68,7 +72,9 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders with tax without showTax set', () => {
|
||||
const subject = () => {
|
||||
return render(<PriceDetails {...defaultPriceDetailsProps} tax={300} />);
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails {...defaultPriceDetailsProps} tax={300} />
|
||||
);
|
||||
};
|
||||
|
||||
const { queryByTestId } = subject();
|
||||
|
@ -80,7 +86,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders with tax, even though tax isnt provided', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails {...defaultPriceDetailsProps} showTax={true} />
|
||||
);
|
||||
};
|
||||
|
@ -97,7 +103,7 @@ describe('PriceDetails', () => {
|
|||
describe('Without tax', () => {
|
||||
it('renders for one day', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'day'}
|
||||
|
@ -114,7 +120,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for multiple days', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'day'}
|
||||
|
@ -131,7 +137,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for one week', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'week'}
|
||||
|
@ -148,7 +154,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for multiple weeks', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'week'}
|
||||
|
@ -165,7 +171,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for one month', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'month'}
|
||||
|
@ -182,7 +188,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for multiple months', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'month'}
|
||||
|
@ -199,7 +205,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for one year', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'year'}
|
||||
|
@ -216,7 +222,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for multiple years', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'year'}
|
||||
|
@ -235,7 +241,7 @@ describe('PriceDetails', () => {
|
|||
describe('With tax', () => {
|
||||
it('renders for one day', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'day'}
|
||||
|
@ -253,7 +259,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for multiple days', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'day'}
|
||||
|
@ -273,7 +279,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for one week', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'week'}
|
||||
|
@ -291,7 +297,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for multiple weeks', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'week'}
|
||||
|
@ -311,7 +317,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for one month', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'month'}
|
||||
|
@ -329,7 +335,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for multiple months', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'month'}
|
||||
|
@ -349,7 +355,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for one year', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'year'}
|
||||
|
@ -367,7 +373,7 @@ describe('PriceDetails', () => {
|
|||
|
||||
it('renders for multiple years', () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<PriceDetails
|
||||
{...defaultPriceDetailsProps}
|
||||
interval={'year'}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import SubscriptionTitle, { SubscriptionTitleProps, titles } from './index';
|
||||
|
||||
import { getLocalizedMessage } from '../../lib/test-utils';
|
||||
import {
|
||||
getLocalizedMessage,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
import { getFtlBundle } from 'fxa-react/lib/test-utils';
|
||||
import { FluentBundle } from '@fluent/bundle';
|
||||
|
||||
|
@ -21,7 +24,9 @@ describe('SubscriptionTitle', () => {
|
|||
});
|
||||
it('renders as expected', async () => {
|
||||
const subject = () => {
|
||||
return render(<SubscriptionTitle {...defaultProps} />);
|
||||
return renderWithLocalizationProvider(
|
||||
<SubscriptionTitle {...defaultProps} />
|
||||
);
|
||||
};
|
||||
const { findByTestId } = subject();
|
||||
const component = await findByTestId('subscription-create-title');
|
||||
|
@ -43,7 +48,9 @@ describe('SubscriptionTitle', () => {
|
|||
|
||||
it('renders as expected for SubscriptionSuccess', async () => {
|
||||
const subject = () => {
|
||||
return render(<SubscriptionTitle screenType="success" />);
|
||||
return renderWithLocalizationProvider(
|
||||
<SubscriptionTitle screenType="success" />
|
||||
);
|
||||
};
|
||||
const { findByTestId } = subject();
|
||||
const component = await findByTestId('subscription-success-title');
|
||||
|
@ -65,7 +72,9 @@ describe('SubscriptionTitle', () => {
|
|||
|
||||
it('renders as expected for PaymentProcessing', async () => {
|
||||
const subject = () => {
|
||||
return render(<SubscriptionTitle screenType="processing" />);
|
||||
return renderWithLocalizationProvider(
|
||||
<SubscriptionTitle screenType="processing" />
|
||||
);
|
||||
};
|
||||
const { findByTestId } = subject();
|
||||
const component = await findByTestId('subscription-processing-title');
|
||||
|
@ -87,7 +96,7 @@ describe('SubscriptionTitle', () => {
|
|||
|
||||
it('renders the subtitle as expected', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<SubscriptionTitle
|
||||
{...{
|
||||
screenType: 'noplanchange',
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { MOCK_PLANS } from '../../lib/test-utils';
|
||||
import {
|
||||
MOCK_PLANS,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
import { TermsAndPrivacy } from './index';
|
||||
import { defaultAppContext, AppContext } from '../../lib/AppContext';
|
||||
import { DEFAULT_PRODUCT_DETAILS } from 'fxa-shared/subscriptions/metadata';
|
||||
|
@ -72,7 +75,7 @@ afterEach(() => {
|
|||
});
|
||||
|
||||
it('renders as expected with a plan with no legal doc links metadata', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<TermsAndPrivacy plan={planWithNoLegalLinks} />
|
||||
);
|
||||
|
||||
|
@ -99,7 +102,7 @@ it('renders as expected with a plan with no legal doc links metadata', () => {
|
|||
});
|
||||
|
||||
it('renders as expected when passed "showFXALinks" option', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<TermsAndPrivacy plan={planWithNoLegalLinks} showFXALinks={true} />
|
||||
);
|
||||
|
||||
|
@ -108,7 +111,9 @@ it('renders as expected when passed "showFXALinks" option', () => {
|
|||
});
|
||||
|
||||
it('renders as expected with default locale', () => {
|
||||
const { queryByTestId } = render(<TermsAndPrivacy plan={plan} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<TermsAndPrivacy plan={plan} />
|
||||
);
|
||||
const termsLink = queryByTestId('terms');
|
||||
expect(termsLink).toBeInTheDocument();
|
||||
expect(termsLink).toHaveAttribute('href', enTermsOfServiceURL);
|
||||
|
@ -118,7 +123,7 @@ it('renders as expected with default locale', () => {
|
|||
});
|
||||
|
||||
it('renders as expected with fr locale', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AppContext.Provider
|
||||
value={{ ...defaultAppContext, navigatorLanguages: ['fr'] }}
|
||||
>
|
||||
|
@ -139,7 +144,7 @@ it('renders as expected with firestore config and default locale', () => {
|
|||
useFirestoreProductConfigs: true,
|
||||
},
|
||||
});
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<TermsAndPrivacy plan={planWithConfiguration} />
|
||||
);
|
||||
const termsLink = queryByTestId('terms');
|
||||
|
@ -156,7 +161,7 @@ it('renders as expected with firestore config and fr locale', () => {
|
|||
useFirestoreProductConfigs: true,
|
||||
},
|
||||
});
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AppContext.Provider
|
||||
value={{ ...defaultAppContext, navigatorLanguages: ['fr'] }}
|
||||
>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useRef } from 'react';
|
||||
import { render, cleanup, fireEvent } from '@testing-library/react';
|
||||
import { cleanup, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { Omit } from '../../lib/types';
|
||||
import ScreenInfo from '../../lib/screen-info';
|
||||
|
@ -10,6 +10,7 @@ import {
|
|||
MIN_HEIGHT_TO_SHOW_TOOLTIP_BELOW,
|
||||
MIN_WIDTH_TO_SHOW_TOOLTIP_BELOW,
|
||||
} from './index';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
const LABEL_TEXT = 'Valid frobnitz required.';
|
||||
|
||||
|
@ -56,7 +57,9 @@ const Subject = (props: SubjectProps) => {
|
|||
};
|
||||
|
||||
it('renders children as label', () => {
|
||||
const { queryByText } = render(<Subject>{LABEL_TEXT}</Subject>);
|
||||
const { queryByText } = renderWithLocalizationProvider(
|
||||
<Subject>{LABEL_TEXT}</Subject>
|
||||
);
|
||||
const result = queryByText(LABEL_TEXT);
|
||||
expect(result).toBeInTheDocument();
|
||||
expect(result).toHaveClass('tooltip');
|
||||
|
@ -66,7 +69,7 @@ it('renders children as label', () => {
|
|||
});
|
||||
|
||||
it('renders with expected id and class names', () => {
|
||||
const { getByText } = render(
|
||||
const { getByText } = renderWithLocalizationProvider(
|
||||
<Subject id="xyzzy" extraClassNames="frobnitz">
|
||||
{LABEL_TEXT}
|
||||
</Subject>
|
||||
|
@ -81,7 +84,7 @@ it('renders with expected id and class names', () => {
|
|||
|
||||
it('handles being dismissible', () => {
|
||||
const onDismiss = jest.fn();
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject dismissible onDismiss={onDismiss}>
|
||||
{LABEL_TEXT}
|
||||
</Subject>
|
||||
|
@ -93,14 +96,16 @@ it('handles being dismissible', () => {
|
|||
});
|
||||
|
||||
it('throws no error if onDismiss was not supplied to dismissable', () => {
|
||||
const { queryByTestId } = render(<Subject dismissible>{LABEL_TEXT}</Subject>);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject dismissible>{LABEL_TEXT}</Subject>
|
||||
);
|
||||
const control = queryByTestId('dismiss-button');
|
||||
expect(control).toBeInTheDocument();
|
||||
fireEvent.click(control as Element);
|
||||
});
|
||||
|
||||
it('displays label above with showBelow=false', () => {
|
||||
const { getByText } = render(
|
||||
const { getByText } = renderWithLocalizationProvider(
|
||||
<Subject showBelow={false}>{LABEL_TEXT}</Subject>
|
||||
);
|
||||
const result = getByText(LABEL_TEXT);
|
||||
|
@ -110,7 +115,7 @@ it('displays label above with showBelow=false', () => {
|
|||
});
|
||||
|
||||
it('displays label above on short window', () => {
|
||||
const { getByText } = render(
|
||||
const { getByText } = renderWithLocalizationProvider(
|
||||
<Subject clientHeight={MIN_HEIGHT_TO_SHOW_TOOLTIP_BELOW - 10}>
|
||||
{LABEL_TEXT}
|
||||
</Subject>
|
||||
|
@ -122,7 +127,7 @@ it('displays label above on short window', () => {
|
|||
});
|
||||
|
||||
it('overrides showBelow={true} on short window', () => {
|
||||
const { getByText } = render(
|
||||
const { getByText } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
showBelow={true}
|
||||
clientHeight={MIN_HEIGHT_TO_SHOW_TOOLTIP_BELOW - 10}
|
||||
|
@ -137,7 +142,7 @@ it('overrides showBelow={true} on short window', () => {
|
|||
});
|
||||
|
||||
it('displays label above on narrow window', () => {
|
||||
const { getByText } = render(
|
||||
const { getByText } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
showBelow={true}
|
||||
clientWidth={MIN_WIDTH_TO_SHOW_TOOLTIP_BELOW - 10}
|
||||
|
@ -152,7 +157,7 @@ it('displays label above on narrow window', () => {
|
|||
});
|
||||
|
||||
it('overrides showBelow={true} on narrow window', () => {
|
||||
const { getByText } = render(
|
||||
const { getByText } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
showBelow={true}
|
||||
clientWidth={MIN_WIDTH_TO_SHOW_TOOLTIP_BELOW - 10}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useCallback, useContext, useRef } from 'react';
|
||||
import { render, cleanup, fireEvent } from '@testing-library/react';
|
||||
import { cleanup, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import {
|
||||
FieldGroup,
|
||||
|
@ -19,13 +19,14 @@ import {
|
|||
State as ValidatorState,
|
||||
MiddlewareReducer as ValidatorMiddlewareReducer,
|
||||
} from '../../lib/validator';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('Form', () => {
|
||||
it('renders a form that provides children with a validator', () => {
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { container } = render(
|
||||
const { container } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<Field fieldType="input" name="foo" label="This is a label">
|
||||
<p>Hi mom</p>
|
||||
|
@ -50,7 +51,7 @@ describe('Form', () => {
|
|||
|
||||
describe('FieldGroup', () => {
|
||||
it('wraps children in className="input-row-group"', () => {
|
||||
const { container } = render(
|
||||
const { container } = renderWithLocalizationProvider(
|
||||
<FieldGroup>
|
||||
<div>Hi mom</div>
|
||||
</FieldGroup>
|
||||
|
@ -62,7 +63,7 @@ describe('FieldGroup', () => {
|
|||
|
||||
describe('Field', () => {
|
||||
it('renders a label when available', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm>
|
||||
<Field fieldType="input" name="foo" label="This is a label">
|
||||
<p>Hi mom</p>
|
||||
|
@ -101,7 +102,9 @@ describe('Field', () => {
|
|||
</TestForm>
|
||||
);
|
||||
};
|
||||
const { container, queryAllByTestId } = render(<Subject />);
|
||||
const { container, queryAllByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
queryAllByTestId('execute').forEach(fireEvent.click);
|
||||
const tooltip = container.querySelector('aside.tooltip');
|
||||
expect(tooltip).not.toBeNull();
|
||||
|
@ -132,7 +135,9 @@ describe('Field', () => {
|
|||
</TestForm>
|
||||
);
|
||||
};
|
||||
const { container, queryAllByTestId } = render(<Subject />);
|
||||
const { container, queryAllByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
queryAllByTestId('execute').forEach(fireEvent.click);
|
||||
const tooltip = container.querySelector('aside.tooltip');
|
||||
expect(tooltip).toBeNull();
|
||||
|
@ -140,7 +145,7 @@ describe('Field', () => {
|
|||
|
||||
it('registers a field with validator state', () => {
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<Field fieldType="input" name="foo">
|
||||
<p>Hi mom</p>
|
||||
|
@ -175,7 +180,7 @@ describe('defaultInputValidator', () => {
|
|||
describe('Input', () => {
|
||||
it('considers an optional field without onValidate as always valid', () => {
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<Input
|
||||
data-testid="input-1"
|
||||
|
@ -193,7 +198,7 @@ describe('Input', () => {
|
|||
|
||||
it('enforces non-empty content in required fields', () => {
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<Input
|
||||
data-testid="input-1"
|
||||
|
@ -241,7 +246,7 @@ describe('Input', () => {
|
|||
});
|
||||
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<Input
|
||||
data-testid="testInput"
|
||||
|
@ -301,7 +306,7 @@ describe('Input', () => {
|
|||
valid: false,
|
||||
error: 'bad thing',
|
||||
});
|
||||
const { container, getByTestId } = render(
|
||||
const { container, getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm>
|
||||
<Input
|
||||
data-testid="testInput"
|
||||
|
@ -352,7 +357,7 @@ describe('StripeElement', () => {
|
|||
it('does nothing if field value is null', () => {
|
||||
const MockStripeElement = buildMockStripeElement(null);
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<StripeElement name="input-1" component={MockStripeElement} />
|
||||
</TestForm>
|
||||
|
@ -369,7 +374,7 @@ describe('StripeElement', () => {
|
|||
error: null,
|
||||
});
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<StripeElement name="input-1" component={MockStripeElement} />
|
||||
</TestForm>
|
||||
|
@ -385,7 +390,7 @@ describe('StripeElement', () => {
|
|||
error: { message: 'game over man' },
|
||||
});
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { container, getByTestId } = render(
|
||||
const { container, getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<StripeElement name="input-1" component={MockStripeElement} />
|
||||
</TestForm>
|
||||
|
@ -422,7 +427,7 @@ describe('StripeElement', () => {
|
|||
const MockStripeElement = buildMockStripeElement(undefined);
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const translatedIsRequired = 'IS REQUIRED TRANSLATED';
|
||||
const { container, getByTestId } = render(
|
||||
const { container, getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<StripeElement
|
||||
data-testid="input-1"
|
||||
|
@ -463,7 +468,7 @@ describe('StripeElement', () => {
|
|||
valid: false,
|
||||
error: expectedError,
|
||||
}));
|
||||
const { container, getByTestId } = render(
|
||||
const { container, getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<StripeElement
|
||||
data-testid="input-1"
|
||||
|
@ -486,7 +491,7 @@ describe('StripeElement', () => {
|
|||
error: { message: 'period.' },
|
||||
});
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { container, getByTestId } = render(
|
||||
const { container, getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<StripeElement name="input-1" component={MockStripeElement} />
|
||||
</TestForm>
|
||||
|
@ -503,7 +508,7 @@ describe('StripeElement', () => {
|
|||
it('handles complete result from contained stripe element', () => {
|
||||
const MockStripeElement = buildMockStripeElement({ complete: true });
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { container, getByTestId } = render(
|
||||
const { container, getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<StripeElement name="input-1" component={MockStripeElement} />
|
||||
</TestForm>
|
||||
|
@ -531,7 +536,7 @@ describe('StripeElement', () => {
|
|||
|
||||
describe('Checkbox', () => {
|
||||
it('renders its own label with a label prop when avaiable', () => {
|
||||
const { container } = render(
|
||||
const { container } = renderWithLocalizationProvider(
|
||||
<TestForm>
|
||||
<Checkbox name="foo" label="nice label" />
|
||||
</TestForm>
|
||||
|
@ -542,7 +547,7 @@ describe('Checkbox', () => {
|
|||
});
|
||||
|
||||
it('renders children as a label with markup when available', () => {
|
||||
const { container } = render(
|
||||
const { container } = renderWithLocalizationProvider(
|
||||
<TestForm>
|
||||
<Checkbox name="foo">
|
||||
nice <span className="label-inner-span">label</span>
|
||||
|
@ -558,7 +563,7 @@ describe('Checkbox', () => {
|
|||
});
|
||||
|
||||
it('accepts an alternate className', () => {
|
||||
const { container } = render(
|
||||
const { container } = renderWithLocalizationProvider(
|
||||
<TestForm>
|
||||
<Checkbox className="fooquux" name="foo" label="nice label" />
|
||||
</TestForm>
|
||||
|
@ -568,7 +573,7 @@ describe('Checkbox', () => {
|
|||
|
||||
it('must be checked to be valid when required', () => {
|
||||
const validatorStateRef = mkValidatorStateRef();
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<TestForm validatorStateRef={validatorStateRef}>
|
||||
<Checkbox data-testid="checkbox" name="foo" required />
|
||||
</TestForm>
|
||||
|
@ -633,7 +638,9 @@ describe('SubmitButton', () => {
|
|||
</TestForm>
|
||||
);
|
||||
};
|
||||
const { queryAllByTestId, getByTestId } = render(<Subject />);
|
||||
const { queryAllByTestId, getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
const validatorFns = queryAllByTestId('execute');
|
||||
|
||||
fireEvent.click(validatorFns[0]);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import React, { useContext } from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { defaultAppContext, AppContext, AppContextType } from './AppContext';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
|
@ -29,7 +30,7 @@ it('passes along given app-global props', () => {
|
|||
accessToken: 'lettherightonein',
|
||||
};
|
||||
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={appContextValue}>
|
||||
<Subject />
|
||||
</AppContext.Provider>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { cleanup, fireEvent, render, waitFor } from '@testing-library/react';
|
||||
import { cleanup, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { CouponDetails } from 'fxa-shared/dto/auth/payments/coupon';
|
||||
import {
|
||||
MozillaSubscription,
|
||||
|
@ -32,6 +32,7 @@ import {
|
|||
// eslint-disable-next-line import/first
|
||||
import { apiInvoicePreview } from '../lib/apiClient';
|
||||
import { Config } from './config';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
jest.mock('../lib/apiClient', () => {
|
||||
return {
|
||||
|
@ -56,7 +57,7 @@ describe('useCheckboxStateResult', () => {
|
|||
};
|
||||
|
||||
it('updates state with checkbox state as expected', () => {
|
||||
const { getByTestId } = render(<Subject />);
|
||||
const { getByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
expect(getByTestId('result')).toHaveTextContent('false');
|
||||
fireEvent.click(getByTestId('checkbox'));
|
||||
expect(getByTestId('result')).toHaveTextContent('true');
|
||||
|
@ -65,7 +66,9 @@ describe('useCheckboxStateResult', () => {
|
|||
});
|
||||
|
||||
it('accepts an initial value', () => {
|
||||
const { getByTestId } = render(<Subject initialState={true} />);
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject initialState={true} />
|
||||
);
|
||||
expect(getByTestId('result')).toHaveTextContent('true');
|
||||
});
|
||||
});
|
||||
|
@ -82,14 +85,14 @@ describe('useNonce', () => {
|
|||
};
|
||||
|
||||
it('should render with an initial nonce', () => {
|
||||
const { getByTestId } = render(<Subject />);
|
||||
const { getByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
const initialNonce = getByTestId('nonce').textContent;
|
||||
expect(initialNonce).toBeDefined();
|
||||
expect(initialNonce).not.toBe('');
|
||||
});
|
||||
|
||||
it('should change nonce on refresh', () => {
|
||||
const { getByTestId } = render(<Subject />);
|
||||
const { getByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
const refreshButton = getByTestId('refresh');
|
||||
|
||||
// Click the button a few times for good measure;
|
||||
|
@ -135,7 +138,7 @@ describe('useReactGA4Setup', () => {
|
|||
enabled: false,
|
||||
},
|
||||
} as Config;
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject config={config} productId="prod_GqM9ToKK62qjkK" />
|
||||
);
|
||||
|
||||
|
@ -150,7 +153,7 @@ describe('useReactGA4Setup', () => {
|
|||
supportedProductIds: '',
|
||||
},
|
||||
} as Config;
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject config={config} productId="prod_GqM9ToKK62qjkK" />
|
||||
);
|
||||
|
||||
|
@ -160,7 +163,7 @@ describe('useReactGA4Setup', () => {
|
|||
|
||||
it('does not initialize ReactGA4 - productId is not in supportedProductIds', () => {
|
||||
const config = mockConfig;
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject config={config} productId="prod_fake" />
|
||||
);
|
||||
|
||||
|
@ -181,7 +184,7 @@ describe('useReactGA4Setup', () => {
|
|||
measurementId: '',
|
||||
},
|
||||
} as Config;
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject config={config} productId="prod_GqM9ToKK62qjkK" />
|
||||
);
|
||||
|
||||
|
@ -197,7 +200,7 @@ describe('useReactGA4Setup', () => {
|
|||
|
||||
it('successfully initialize ReactGA4', () => {
|
||||
const config = mockConfig;
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject config={config} productId="prod_GqM9ToKK62qjkK" />
|
||||
);
|
||||
|
||||
|
@ -219,7 +222,7 @@ describe('useReactGA4Setup', () => {
|
|||
supportedProductIds: 'prod_test_1,prod_GqM9ToKK62qjkK,prod_test_2',
|
||||
},
|
||||
} as Config;
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject config={config} productId="prod_GqM9ToKK62qjkK" />
|
||||
);
|
||||
|
||||
|
@ -240,7 +243,7 @@ describe('useReactGA4Setup', () => {
|
|||
testMode: true,
|
||||
},
|
||||
} as Config;
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject config={config} productId="prod_GqM9ToKK62qjkK" />
|
||||
);
|
||||
|
||||
|
@ -284,7 +287,7 @@ describe('useInfoBoxMessage', () => {
|
|||
};
|
||||
|
||||
it('coupon has no value', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject coupon={undefined} selectedPlan={selectedPlan} />
|
||||
);
|
||||
expect(queryByTestId('info-box-message')).not.toBeInTheDocument();
|
||||
|
@ -292,7 +295,7 @@ describe('useInfoBoxMessage', () => {
|
|||
});
|
||||
|
||||
it('coupon type is "forever"', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
coupon={{ ...coupon, type: 'forever' }}
|
||||
selectedPlan={selectedPlan}
|
||||
|
@ -303,7 +306,7 @@ describe('useInfoBoxMessage', () => {
|
|||
});
|
||||
|
||||
it('coupon type is an unexpected value', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
coupon={{ ...coupon, type: 'unexpected-value' }}
|
||||
selectedPlan={selectedPlan}
|
||||
|
@ -314,7 +317,7 @@ describe('useInfoBoxMessage', () => {
|
|||
});
|
||||
|
||||
it('coupon type is "once"', () => {
|
||||
const { queryByTestId, getByTestId } = render(
|
||||
const { queryByTestId, getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
coupon={{ ...coupon, type: 'once' }}
|
||||
selectedPlan={selectedPlan}
|
||||
|
@ -328,7 +331,7 @@ describe('useInfoBoxMessage', () => {
|
|||
});
|
||||
|
||||
it('coupon type is "repeating" plan interval greater than coupon duration', () => {
|
||||
const { queryByTestId, getByTestId } = render(
|
||||
const { queryByTestId, getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
coupon={{ ...coupon, type: 'repeating' }}
|
||||
selectedPlan={{ ...selectedPlan, interval_count: 6 }}
|
||||
|
@ -342,7 +345,7 @@ describe('useInfoBoxMessage', () => {
|
|||
});
|
||||
|
||||
it('coupon type is "repeating" plan interval equal to coupon duration', () => {
|
||||
const { queryByTestId, getByTestId } = render(
|
||||
const { queryByTestId, getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
coupon={{ ...coupon, type: 'repeating' }}
|
||||
selectedPlan={selectedPlan}
|
||||
|
@ -361,7 +364,7 @@ describe('useInfoBoxMessage', () => {
|
|||
durationInMonths: 2,
|
||||
type: 'repeating',
|
||||
};
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject coupon={couponLongerDuration} selectedPlan={selectedPlan} />
|
||||
);
|
||||
const date = new Date();
|
||||
|
@ -485,7 +488,9 @@ describe('useFetchInvoicePreview', () => {
|
|||
});
|
||||
|
||||
it('returns invoicePreview no subscriptions', async () => {
|
||||
const { queryByTestId } = render(<Subject planId={PLAN_ID} />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject planId={PLAN_ID} />
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByTestId('loading')).toBeInTheDocument();
|
||||
|
@ -499,7 +504,7 @@ describe('useFetchInvoicePreview', () => {
|
|||
});
|
||||
|
||||
it('returns invoicePreview no promotionCode', async () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject planId={PLAN_ID} customerSubscriptions={customerSubscriptions} />
|
||||
);
|
||||
|
||||
|
@ -515,7 +520,7 @@ describe('useFetchInvoicePreview', () => {
|
|||
});
|
||||
|
||||
it('returns invoicePreview with promotionCode', async () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
planId={PLAN_ID}
|
||||
customerSubscriptions={customerSubscriptionsWithPromotionCode}
|
||||
|
@ -537,7 +542,7 @@ describe('useFetchInvoicePreview', () => {
|
|||
});
|
||||
|
||||
it('empty planId', async () => {
|
||||
const { queryByTestId } = render(<Subject />);
|
||||
const { queryByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByTestId('no-invoice')).toBeInTheDocument();
|
||||
|
@ -548,7 +553,7 @@ describe('useFetchInvoicePreview', () => {
|
|||
|
||||
it('invoicePreview throws error', async () => {
|
||||
(apiInvoicePreview as jest.Mock).mockClear().mockRejectedValue({});
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject planId={PLAN_ID} customerSubscriptions={customerSubscriptions} />
|
||||
);
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useContext, ReactNode } from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { Provider as ReduxProvider } from 'react-redux';
|
||||
import { AppContext, AppContextType } from '../../src/lib/AppContext';
|
||||
import { config, updateConfig } from '../../src/lib/config';
|
||||
|
@ -26,6 +27,8 @@ import {
|
|||
SubsequentInvoicePreview,
|
||||
} from 'fxa-shared/dto/auth/payments/invoice';
|
||||
|
||||
import AppLocalizationProvider from 'fxa-react/lib/AppLocalizationProvider';
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
|
@ -1086,4 +1089,25 @@ export function getLocalizedMessage(
|
|||
return bundle.formatPattern(localizedMessage.value, { ...args });
|
||||
}
|
||||
|
||||
export function renderWithLocalizationProvider(
|
||||
children,
|
||||
messages = { en: ['testo: lol'] }
|
||||
) {
|
||||
// by default fluent warns about missing messages, but there's no way to
|
||||
// disable it right now. see
|
||||
// https://github.com/projectfluent/fluent.js/issues/411
|
||||
return render(withLocalizationProvider(children, messages));
|
||||
}
|
||||
|
||||
export function withLocalizationProvider(
|
||||
children,
|
||||
messages = { en: ['testo: lol'] }
|
||||
) {
|
||||
return (
|
||||
<AppLocalizationProvider messages={messages}>
|
||||
{children}
|
||||
</AppLocalizationProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default MockApp;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useCallback, useContext } from 'react';
|
||||
import { render, cleanup, fireEvent } from '@testing-library/react';
|
||||
import { cleanup, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import {
|
||||
mainReducer,
|
||||
|
@ -10,6 +10,7 @@ import {
|
|||
defaultState as validatorDefaultState,
|
||||
Action as ValidatorAction,
|
||||
} from './validator';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
|
@ -28,7 +29,7 @@ describe('useValidatorState', () => {
|
|||
const validator = useValidatorState();
|
||||
return <div>{JSON.stringify(validator.state)}</div>;
|
||||
};
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -192,7 +193,7 @@ const runAgainstValidator = (...fns: Array<(validator: Validator) => any>) => {
|
|||
return nextState;
|
||||
};
|
||||
|
||||
const { queryAllByTestId } = render(
|
||||
const { queryAllByTestId } = renderWithLocalizationProvider(
|
||||
<TestContainer {...{ middleware, results, fns }} />
|
||||
);
|
||||
|
||||
|
@ -229,11 +230,10 @@ const TestContainer = ({
|
|||
|
||||
const TestFn = ({ execute }: { execute: (validator: Validator) => any }) => {
|
||||
const { validator, results } = useContext(TestContext) as TestContextValue;
|
||||
const onClick = useCallback(() => results.push(execute(validator)), [
|
||||
results,
|
||||
execute,
|
||||
validator,
|
||||
]);
|
||||
const onClick = useCallback(
|
||||
() => results.push(execute(validator)),
|
||||
[results, execute, validator]
|
||||
);
|
||||
return (
|
||||
<button data-testid="execute" onClick={onClick}>
|
||||
Execute
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import {
|
||||
render,
|
||||
cleanup,
|
||||
fireEvent,
|
||||
act,
|
||||
screen,
|
||||
} from '@testing-library/react';
|
||||
import { cleanup, fireEvent, act, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import waitForExpect from 'wait-for-expect';
|
||||
|
||||
|
@ -24,6 +18,7 @@ import {
|
|||
elementChangeResponse,
|
||||
MOCK_CHECKOUT_TOKEN,
|
||||
MOCK_PAYPAL_SUBSCRIPTION_RESULT,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
|
||||
import Checkout, { CheckoutProps } from './index';
|
||||
|
@ -187,7 +182,7 @@ describe('routes/Checkout', () => {
|
|||
|
||||
it('renders as expected', async () => {
|
||||
await act(async () => {
|
||||
render(<Subject planId="testo" />);
|
||||
renderWithLocalizationProvider(<Subject planId="testo" />);
|
||||
});
|
||||
|
||||
const { findByTestId, getByTestId } = screen;
|
||||
|
@ -221,7 +216,7 @@ describe('routes/Checkout', () => {
|
|||
|
||||
it('displays checkbox tooltip error when unchecking checkbox', async () => {
|
||||
await act(async () => {
|
||||
render(<Subject planId="testo" />);
|
||||
renderWithLocalizationProvider(<Subject planId="testo" />);
|
||||
});
|
||||
const { queryByTestId, findByTestId, queryByText } = screen;
|
||||
const paymentFormContainer = queryByTestId('payment-form-container');
|
||||
|
@ -245,7 +240,7 @@ describe('routes/Checkout', () => {
|
|||
|
||||
it('displays checkbox tooltip error when unchecked and clicking on disabled form', async () => {
|
||||
await act(async () => {
|
||||
render(<Subject planId="testo" />);
|
||||
renderWithLocalizationProvider(<Subject planId="testo" />);
|
||||
});
|
||||
const { queryByTestId, queryByText } = screen;
|
||||
const paymentFormContainer = queryByTestId('payment-form-container');
|
||||
|
@ -265,7 +260,7 @@ describe('routes/Checkout', () => {
|
|||
});
|
||||
|
||||
it('displays an error with invalid product ID', async () => {
|
||||
const { findByTestId, queryByTestId } = render(
|
||||
const { findByTestId, queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject productId="bad_product" />
|
||||
);
|
||||
await findByTestId('no-such-plan-error');
|
||||
|
@ -274,13 +269,15 @@ describe('routes/Checkout', () => {
|
|||
|
||||
it('displays an error on failure to load plans', async () => {
|
||||
(apiFetchPlans as jest.Mock).mockRejectedValue({});
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
const errorEl = await findByTestId('error-loading-plans');
|
||||
expect(errorEl).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays an error when selecting an inactive / archived plan', async () => {
|
||||
const { findByTestId } = render(<Subject planId={INACTIVE_PLAN_ID} />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject planId={INACTIVE_PLAN_ID} />
|
||||
);
|
||||
const errorEl = await findByTestId('no-such-plan-error');
|
||||
expect(errorEl).toBeInTheDocument();
|
||||
});
|
||||
|
@ -322,7 +319,7 @@ describe('routes/Checkout', () => {
|
|||
|
||||
it('creates the account and subscription successfully', async () => {
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -349,7 +346,7 @@ describe('routes/Checkout', () => {
|
|||
.mockResolvedValueOnce({ ...CUSTOMER, subscriptions: [] })
|
||||
.mockResolvedValueOnce(CUSTOMER);
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -364,7 +361,7 @@ describe('routes/Checkout', () => {
|
|||
FXA_SIGNUP_ERROR
|
||||
);
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -393,7 +390,7 @@ describe('routes/Checkout', () => {
|
|||
error: MOCK_STRIPE_CARD_ERROR,
|
||||
});
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -423,7 +420,7 @@ describe('routes/Checkout', () => {
|
|||
MOCK_FXA_POST_PASSWORDLESS_SUB_ERROR
|
||||
);
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -455,7 +452,7 @@ describe('routes/Checkout', () => {
|
|||
MOCK_FXA_POST_PASSWORDLESS_SUB_ERROR
|
||||
);
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -488,7 +485,7 @@ describe('routes/Checkout', () => {
|
|||
.mockRejectedValue(MOCK_CURRENCY_ERROR);
|
||||
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -508,7 +505,7 @@ describe('routes/Checkout', () => {
|
|||
describe('newsletter', () => {
|
||||
it('POSTs to /newsletters if the newsletter checkbox is checked when subscription succeeds', async () => {
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
const shouldSubscribeToNewsletter = true;
|
||||
await fillOutZeForm(shouldSubscribeToNewsletter);
|
||||
|
@ -520,7 +517,7 @@ describe('routes/Checkout', () => {
|
|||
|
||||
it('Does not POST to /newsletters if the newsletter checkbox is unchecked when subscription succeeds', async () => {
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
const shouldSubscribeToNewsletter = false;
|
||||
await fillOutZeForm(shouldSubscribeToNewsletter);
|
||||
|
@ -536,7 +533,7 @@ describe('routes/Checkout', () => {
|
|||
error: MOCK_STRIPE_CARD_ERROR,
|
||||
});
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
const shouldSubscribeToNewsletter = true;
|
||||
await fillOutZeForm(shouldSubscribeToNewsletter);
|
||||
|
@ -551,7 +548,7 @@ describe('routes/Checkout', () => {
|
|||
FXA_NEWSLETTER_SIGNUP_ERROR
|
||||
);
|
||||
await act(async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
});
|
||||
const shouldSubscribeToNewsletter = true;
|
||||
await fillOutZeForm(shouldSubscribeToNewsletter);
|
||||
|
@ -610,7 +607,9 @@ describe('routes/Checkout', () => {
|
|||
);
|
||||
};
|
||||
await act(async () => {
|
||||
render(<Subject paypalButtonBase={paypalButtonBase} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject paypalButtonBase={paypalButtonBase} />
|
||||
);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -646,7 +645,9 @@ describe('routes/Checkout', () => {
|
|||
);
|
||||
};
|
||||
await act(async () => {
|
||||
render(<Subject paypalButtonBase={paypalButtonBase} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject paypalButtonBase={paypalButtonBase} />
|
||||
);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -680,7 +681,9 @@ describe('routes/Checkout', () => {
|
|||
);
|
||||
};
|
||||
await act(async () => {
|
||||
render(<Subject paypalButtonBase={paypalButtonBase} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject paypalButtonBase={paypalButtonBase} />
|
||||
);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -714,7 +717,9 @@ describe('routes/Checkout', () => {
|
|||
);
|
||||
};
|
||||
await act(async () => {
|
||||
render(<Subject paypalButtonBase={paypalButtonBase} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject paypalButtonBase={paypalButtonBase} />
|
||||
);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -744,7 +749,9 @@ describe('routes/Checkout', () => {
|
|||
);
|
||||
};
|
||||
await act(async () => {
|
||||
render(<Subject paypalButtonBase={paypalButtonBase} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject paypalButtonBase={paypalButtonBase} />
|
||||
);
|
||||
});
|
||||
await fillOutZeForm();
|
||||
await waitForExpect(() => {
|
||||
|
@ -777,7 +784,9 @@ describe('routes/Checkout', () => {
|
|||
);
|
||||
};
|
||||
await act(async () => {
|
||||
render(<Subject paypalButtonBase={paypalButtonBase} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject paypalButtonBase={paypalButtonBase} />
|
||||
);
|
||||
});
|
||||
const shouldSubscribeToNewsletter = true;
|
||||
await fillOutZeForm(shouldSubscribeToNewsletter);
|
||||
|
@ -803,7 +812,9 @@ describe('routes/Checkout', () => {
|
|||
);
|
||||
};
|
||||
await act(async () => {
|
||||
render(<Subject paypalButtonBase={paypalButtonBase} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject paypalButtonBase={paypalButtonBase} />
|
||||
);
|
||||
});
|
||||
const shouldSubscribeToNewsletter = false;
|
||||
await fillOutZeForm(shouldSubscribeToNewsletter);
|
||||
|
@ -826,7 +837,9 @@ describe('routes/Checkout', () => {
|
|||
);
|
||||
};
|
||||
await act(async () => {
|
||||
render(<Subject paypalButtonBase={paypalButtonBase} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject paypalButtonBase={paypalButtonBase} />
|
||||
);
|
||||
});
|
||||
const shouldSubscribeToNewsletter = true;
|
||||
await fillOutZeForm(shouldSubscribeToNewsletter);
|
||||
|
@ -851,7 +864,9 @@ describe('routes/Checkout', () => {
|
|||
);
|
||||
};
|
||||
await act(async () => {
|
||||
render(<Subject paypalButtonBase={paypalButtonBase} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject paypalButtonBase={paypalButtonBase} />
|
||||
);
|
||||
});
|
||||
const shouldSubscribeToNewsletter = true;
|
||||
await fillOutZeForm(shouldSubscribeToNewsletter);
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { MockApp, MOCK_CUSTOMER } from '../../../lib/test-utils';
|
||||
import {
|
||||
MockApp,
|
||||
MOCK_CUSTOMER,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../../lib/test-utils';
|
||||
import { PLAN, SELECTED_PLAN, PROFILE } from '../../../lib/mock-data';
|
||||
import { SignInLayout } from '../../../components/AppLayout';
|
||||
import IapRoadblock, { IapRoadblockProps } from './index';
|
||||
|
@ -34,7 +37,7 @@ const MOCK_PROPS: IapRoadblockProps = {
|
|||
describe('routes/Product/IapRoadblock', () => {
|
||||
it('renders as expected', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<MockApp>
|
||||
<SignInLayout>
|
||||
<IapRoadblock {...MOCK_PROPS} />
|
||||
|
@ -56,7 +59,7 @@ describe('routes/Product/IapRoadblock', () => {
|
|||
|
||||
it('displays messaging to contact support for help in upgrading', async () => {
|
||||
const subject = () => {
|
||||
return render(
|
||||
return renderWithLocalizationProvider(
|
||||
<MockApp>
|
||||
<SignInLayout>
|
||||
<IapRoadblock
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { MockApp } from '../../../lib/test-utils';
|
||||
import {
|
||||
MockApp,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../../lib/test-utils';
|
||||
import { SELECTED_PLAN, PROFILE } from '../../../lib/mock-data';
|
||||
import { SignInLayout } from '../../../components/AppLayout';
|
||||
import SubscriptionChangeRoadblock, {
|
||||
|
@ -27,7 +29,7 @@ const Subject = () => {
|
|||
|
||||
describe('routes/Product/SubscriptionDowngradeRoadblock', () => {
|
||||
it('renders as expected', async () => {
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
const titleEl = await findByTestId('subscription-noplanchange-title');
|
||||
expect(titleEl).toBeInTheDocument();
|
||||
const errorEl = await findByTestId('payment-error');
|
||||
|
|
|
@ -4,13 +4,7 @@
|
|||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { PaymentMethod } from '@stripe/stripe-js';
|
||||
import {
|
||||
act,
|
||||
cleanup,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
} from '@testing-library/react';
|
||||
import { act, cleanup, fireEvent, screen } from '@testing-library/react';
|
||||
import waitForExpect from 'wait-for-expect';
|
||||
|
||||
import SubscriptionCreate, { SubscriptionCreateProps } from '.';
|
||||
|
@ -39,6 +33,7 @@ import {
|
|||
MOCK_PAYPAL_SUBSCRIPTION_RESULT,
|
||||
MockApp,
|
||||
mockStripeElementOnChangeFns,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../../lib/test-utils';
|
||||
import { PickPartial } from '../../../lib/types';
|
||||
|
||||
|
@ -127,7 +122,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
});
|
||||
|
||||
it('renders as expected', async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
const { queryByTestId, queryByText } = screen;
|
||||
const subscriptionCreateTitle = queryByTestId('subscription-create-title');
|
||||
expect(subscriptionCreateTitle).toBeInTheDocument();
|
||||
|
@ -153,7 +148,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
});
|
||||
|
||||
it('displays checkbox tooltip error when unchecking checkbox', async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
const { queryByTestId, findByTestId, queryByText } = screen;
|
||||
const paymentFormContainer = queryByTestId('payment-form-container');
|
||||
expect(paymentFormContainer).toBeInTheDocument();
|
||||
|
@ -175,7 +170,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
});
|
||||
|
||||
it('displays checkbox tooltip error when unchecked and clicking on disabled form', async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
const { queryByTestId, queryByText } = screen;
|
||||
const paymentFormContainer = queryByTestId('payment-form-container');
|
||||
expect(paymentFormContainer).toBeInTheDocument();
|
||||
|
@ -199,7 +194,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
return <button data-testid="paypal-button" />;
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
paypalButtonBase: MockedButtonBase,
|
||||
|
@ -226,7 +221,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
return <button data-testid="paypal-button" />;
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject customer={CUSTOMER} paypalButtonBase={MockedButtonBase} />
|
||||
);
|
||||
});
|
||||
|
@ -244,7 +239,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
return <button data-testid="paypal-button" />;
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customer={PAYPAL_CUSTOMER}
|
||||
paypalButtonBase={MockedButtonBase}
|
||||
|
@ -260,7 +255,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
});
|
||||
|
||||
it('renders as expected for mobile', async () => {
|
||||
render(<Subject isMobile={true} />);
|
||||
renderWithLocalizationProvider(<Subject isMobile={true} />);
|
||||
const { queryByTestId } = screen;
|
||||
const subscriptionCreateTitle = queryByTestId('subscription-create-title');
|
||||
expect(subscriptionCreateTitle).toBeInTheDocument();
|
||||
|
@ -280,7 +275,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
refreshSubscriptions = jest.fn(),
|
||||
...props
|
||||
}) {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
apiClientOverrides,
|
||||
|
@ -606,7 +601,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
};
|
||||
const refreshSubscriptions = jest.fn();
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
apiClientOverrides,
|
||||
|
@ -642,7 +637,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
apiCreateCustomer: jest.fn(),
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
customer: null,
|
||||
|
@ -869,7 +864,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
};
|
||||
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
apiClientOverrides,
|
||||
|
@ -893,7 +888,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
return <button data-testid="paypal-button" onClick={onError} />;
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
paypalButtonBase: MockedButtonBase,
|
||||
|
@ -927,7 +922,7 @@ describe('routes/Product/SubscriptionCreate', () => {
|
|||
.mockRejectedValue({ code: 'barf apiCapturePaypalPayment' }),
|
||||
};
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
apiClientOverrides,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { config as defaultConfig } from '../../../lib/config';
|
||||
import { AppContext, defaultAppContext } from '../../../lib/AppContext';
|
||||
|
@ -8,6 +8,7 @@ import {
|
|||
MOCK_PLANS,
|
||||
MOCK_PROFILE,
|
||||
MOCK_CUSTOMER,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../../lib/test-utils';
|
||||
|
||||
import { SubscriptionSuccess } from './index';
|
||||
|
@ -44,7 +45,7 @@ function assertRedirectForProduct(
|
|||
product_name,
|
||||
configuration: planConfiguration,
|
||||
};
|
||||
const { getByTestId } = render(
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={appContextValue}>
|
||||
<SubscriptionSuccess
|
||||
{...{
|
||||
|
@ -126,7 +127,7 @@ describe('SubscriptionSuccess', () => {
|
|||
});
|
||||
|
||||
it('renders the PlanDetails component on mobile', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={defaultAppContext}>
|
||||
<SubscriptionSuccess
|
||||
{...{
|
||||
|
@ -144,7 +145,7 @@ describe('SubscriptionSuccess', () => {
|
|||
});
|
||||
|
||||
it('renders the coupon form component when a coupon is present', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={defaultAppContext}>
|
||||
<SubscriptionSuccess
|
||||
{...{
|
||||
|
@ -171,7 +172,7 @@ describe('SubscriptionSuccess', () => {
|
|||
});
|
||||
|
||||
it('does not renders the coupon form component when a coupon is not present', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={defaultAppContext}>
|
||||
<SubscriptionSuccess
|
||||
{...{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import TestRenderer from 'react-test-renderer';
|
||||
import { render, cleanup, fireEvent } from '@testing-library/react';
|
||||
import { cleanup, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { APIError } from '../../../lib/apiClient';
|
||||
|
@ -20,6 +20,8 @@ import {
|
|||
MOCK_PREVIEW_INVOICE_WITH_TAX_INCLUSIVE,
|
||||
MOCK_PREVIEW_INVOICE_NO_TAX,
|
||||
MOCK_PREVIEW_INVOICE_WITH_ZERO_TAX_EXCLUSIVE,
|
||||
renderWithLocalizationProvider,
|
||||
withLocalizationProvider,
|
||||
} from '../../../lib/test-utils';
|
||||
import { getFtlBundle } from 'fxa-react/lib/test-utils';
|
||||
import { FluentBundle, FluentNumber } from '@fluent/bundle';
|
||||
|
@ -57,9 +59,10 @@ async function rendersAsExpected(
|
|||
invoicePreview = MOCK_PREVIEW_INVOICE_NO_TAX,
|
||||
selectedPlan = SELECTED_PLAN
|
||||
) {
|
||||
const { findByTestId, queryByTestId, container } = render(
|
||||
<Subject props={{ upgradeFromPlan, invoicePreview, selectedPlan }} />
|
||||
);
|
||||
const { findByTestId, queryByTestId, container } =
|
||||
renderWithLocalizationProvider(
|
||||
<Subject props={{ upgradeFromPlan, invoicePreview, selectedPlan }} />
|
||||
);
|
||||
await findByTestId('subscription-upgrade');
|
||||
|
||||
// Could do some more content-based tests here, but basically just a
|
||||
|
@ -141,7 +144,7 @@ describe('routes/Product/SubscriptionUpgrade', () => {
|
|||
useStripeAutomaticTax: true,
|
||||
},
|
||||
});
|
||||
const { findByTestId, queryByTestId } = render(
|
||||
const { findByTestId, queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
props={{
|
||||
invoicePreview: MOCK_PREVIEW_INVOICE_WITH_TAX_INCLUSIVE,
|
||||
|
@ -161,7 +164,7 @@ describe('routes/Product/SubscriptionUpgrade', () => {
|
|||
useStripeAutomaticTax: true,
|
||||
},
|
||||
});
|
||||
const { findByTestId, queryByTestId } = render(
|
||||
const { findByTestId, queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
props={{
|
||||
invoicePreview: MOCK_PREVIEW_INVOICE_WITH_TAX_EXCLUSIVE,
|
||||
|
@ -181,7 +184,7 @@ describe('routes/Product/SubscriptionUpgrade', () => {
|
|||
useStripeAutomaticTax: true,
|
||||
},
|
||||
});
|
||||
const { findByTestId, queryByTestId } = render(
|
||||
const { findByTestId, queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
props={{
|
||||
invoicePreview: MOCK_PREVIEW_INVOICE_WITH_ZERO_TAX_EXCLUSIVE,
|
||||
|
@ -198,7 +201,7 @@ describe('routes/Product/SubscriptionUpgrade', () => {
|
|||
it('can be submitted after confirmation is checked', async () => {
|
||||
const updateSubscriptionPlanAndRefresh = jest.fn();
|
||||
|
||||
const { findByTestId, getByTestId } = render(
|
||||
const { findByTestId, getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
props={{
|
||||
updateSubscriptionPlanAndRefresh,
|
||||
|
@ -223,7 +226,7 @@ describe('routes/Product/SubscriptionUpgrade', () => {
|
|||
});
|
||||
|
||||
it('displays a loading spinner while submitting', async () => {
|
||||
const { findByTestId, getByTestId } = render(
|
||||
const { findByTestId, getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
props={{
|
||||
updateSubscriptionPlanStatus: {
|
||||
|
@ -242,19 +245,20 @@ describe('routes/Product/SubscriptionUpgrade', () => {
|
|||
it('displays a dialog when updating subscription results in error', async () => {
|
||||
const expectedMessage = 'game over man';
|
||||
|
||||
const { findByTestId, getByTestId, getByText } = render(
|
||||
<Subject
|
||||
props={{
|
||||
updateSubscriptionPlanStatus: {
|
||||
error: new APIError({
|
||||
message: expectedMessage,
|
||||
}),
|
||||
loading: false,
|
||||
result: null,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const { findByTestId, getByTestId, getByText } =
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
props={{
|
||||
updateSubscriptionPlanStatus: {
|
||||
error: new APIError({
|
||||
message: expectedMessage,
|
||||
}),
|
||||
loading: false,
|
||||
result: null,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
await findByTestId('subscription-upgrade');
|
||||
|
||||
expect(getByTestId('error-plan-update-failed')).toBeInTheDocument();
|
||||
|
@ -262,7 +266,9 @@ describe('routes/Product/SubscriptionUpgrade', () => {
|
|||
});
|
||||
|
||||
it('calls updateSubscriptionPlanMounted and updateSubscriptionPlanEngaged', async () => {
|
||||
const { findByTestId, getByTestId } = render(<Subject />);
|
||||
const { findByTestId, getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
await findByTestId('subscription-upgrade');
|
||||
fireEvent.click(getByTestId('confirm'));
|
||||
expect(updateSubscriptionPlanMounted).toBeCalledTimes(1);
|
||||
|
@ -288,7 +294,9 @@ describe('PlanDetailsCard', () => {
|
|||
function runTests(plan: Plan, expectedMsgId: string, expectedMsg: string) {
|
||||
const props = { plan: plan };
|
||||
|
||||
const testRenderer = TestRenderer.create(<PlanDetailsCard {...props} />);
|
||||
const testRenderer = TestRenderer.create(
|
||||
withLocalizationProvider(<PlanDetailsCard {...props} />)
|
||||
);
|
||||
const testInstance = testRenderer.root;
|
||||
const planPriceComponent = testInstance.findByProps({
|
||||
id: expectedMsgId,
|
||||
|
@ -309,7 +317,9 @@ describe('PlanDetailsCard', () => {
|
|||
|
||||
const props = { plan: plan };
|
||||
|
||||
const testRenderer = TestRenderer.create(<PlanDetailsCard {...props} />);
|
||||
const testRenderer = TestRenderer.create(
|
||||
withLocalizationProvider(<PlanDetailsCard {...props} />)
|
||||
);
|
||||
const testInstance = testRenderer.root;
|
||||
const planPriceComponent = testInstance.findByProps({
|
||||
id: 'plan-details-product',
|
||||
|
@ -326,7 +336,9 @@ describe('PlanDetailsCard', () => {
|
|||
|
||||
const props = { plan: plan };
|
||||
|
||||
const testRenderer = TestRenderer.create(<PlanDetailsCard {...props} />);
|
||||
const testRenderer = TestRenderer.create(
|
||||
withLocalizationProvider(<PlanDetailsCard {...props} />)
|
||||
);
|
||||
const testInstance = testRenderer.root;
|
||||
const planPriceComponent = testInstance.findByProps({
|
||||
id: 'plan-details-product',
|
||||
|
|
|
@ -2,11 +2,7 @@
|
|||
* @jest-environment jsdom
|
||||
*/
|
||||
import React from 'react';
|
||||
import {
|
||||
render,
|
||||
cleanup,
|
||||
waitForElementToBeRemoved,
|
||||
} from '@testing-library/react';
|
||||
import { cleanup, waitForElementToBeRemoved } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import noc from 'nock';
|
||||
|
||||
|
@ -29,6 +25,7 @@ import {
|
|||
mockOptionsResponses,
|
||||
INACTIVE_PLAN_ID,
|
||||
MOCK_PREVIEW_INVOICE_NO_TAX,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
|
||||
import { SignInLayout } from '../../components/AppLayout';
|
||||
|
@ -196,7 +193,8 @@ describe('routes/Product', () => {
|
|||
'Access-Control-Allow-Origin': '*',
|
||||
}),
|
||||
];
|
||||
const { findAllByText, queryByText, queryAllByText } = render(<Subject />);
|
||||
const { findAllByText, queryByText, queryAllByText } =
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
await findAllByText('Set up your subscription');
|
||||
expect(
|
||||
|
@ -229,7 +227,7 @@ describe('routes/Product', () => {
|
|||
'Access-Control-Allow-Origin': '*',
|
||||
}),
|
||||
];
|
||||
const { findByTestId, queryByTestId } = render(
|
||||
const { findByTestId, queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject productId="bad_product" />
|
||||
);
|
||||
await waitForElementToBeRemoved(queryByTestId('loading-overlay'));
|
||||
|
@ -268,7 +266,7 @@ describe('routes/Product', () => {
|
|||
'Access-Control-Allow-Origin': '*',
|
||||
}),
|
||||
];
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
const errorEl = await findByTestId('error-loading-profile');
|
||||
expect(errorEl).toBeInTheDocument();
|
||||
expectNockScopesDone(apiMocks);
|
||||
|
@ -286,7 +284,7 @@ describe('routes/Product', () => {
|
|||
)
|
||||
.reply(200, MOCK_CUSTOMER),
|
||||
];
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
const errorEl = await findByTestId('error-loading-plans');
|
||||
expect(errorEl).toBeInTheDocument();
|
||||
expectNockScopesDone(apiMocks);
|
||||
|
@ -310,7 +308,9 @@ describe('routes/Product', () => {
|
|||
'Access-Control-Allow-Origin': '*',
|
||||
}),
|
||||
];
|
||||
const { findByTestId } = render(<Subject planId={INACTIVE_PLAN_ID} />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject planId={INACTIVE_PLAN_ID} />
|
||||
);
|
||||
const errorEl = await findByTestId('no-such-plan-error');
|
||||
expect(errorEl).toBeInTheDocument();
|
||||
expectNockScopesDone(apiMocks);
|
||||
|
@ -346,7 +346,7 @@ describe('routes/Product', () => {
|
|||
'Access-Control-Allow-Origin': '*',
|
||||
}),
|
||||
];
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
const errorEl = await findByTestId('error-loading-customer');
|
||||
expect(errorEl).toBeInTheDocument();
|
||||
expectNockScopesDone(apiMocks);
|
||||
|
@ -382,7 +382,7 @@ describe('routes/Product', () => {
|
|||
'Access-Control-Allow-Origin': '*',
|
||||
}),
|
||||
];
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
const errorEl = await findByTestId('product-invoice-preview-error');
|
||||
expect(errorEl).toBeInTheDocument();
|
||||
expectNockScopesDone(apiMocks);
|
||||
|
@ -422,7 +422,7 @@ describe('routes/Product', () => {
|
|||
'Access-Control-Allow-Origin': '*',
|
||||
}),
|
||||
];
|
||||
const { findAllByText } = render(<Subject />);
|
||||
const { findAllByText } = renderWithLocalizationProvider(<Subject />);
|
||||
const headingEls = await findAllByText('Set up your subscription');
|
||||
expect(headingEls.length).toBeGreaterThan(0);
|
||||
expectNockScopesDone(apiMocks);
|
||||
|
@ -462,7 +462,7 @@ describe('routes/Product', () => {
|
|||
'Access-Control-Allow-Origin': '*',
|
||||
}),
|
||||
];
|
||||
const { findAllByText } = render(<Subject />);
|
||||
const { findAllByText } = renderWithLocalizationProvider(<Subject />);
|
||||
const headingEls = await findAllByText('Set up your subscription');
|
||||
expect(headingEls.length).toBeGreaterThan(0);
|
||||
expectNockScopesDone(apiMocks);
|
||||
|
@ -473,7 +473,7 @@ describe('routes/Product', () => {
|
|||
planId: 'plan_upgrade',
|
||||
planEligibility: 'upgrade',
|
||||
});
|
||||
const { findByTestId } = render(
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
planId: 'plan_upgrade',
|
||||
|
@ -496,7 +496,7 @@ describe('routes/Product', () => {
|
|||
planId: 'plan_no_upgrade',
|
||||
planEligibility: 'create',
|
||||
});
|
||||
const { findAllByText, queryByTestId } = render(
|
||||
const { findAllByText, queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
planId: 'plan_no_upgrade',
|
||||
|
@ -516,7 +516,7 @@ describe('routes/Product', () => {
|
|||
|
||||
it('does not allow a downgrade', async () => {
|
||||
const apiMocks = initSubscribedApiMocks({ planId: 'plan_no_downgrade' });
|
||||
const { findByTestId } = render(
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
planId: 'plan_no_downgrade',
|
||||
|
@ -536,7 +536,7 @@ describe('routes/Product', () => {
|
|||
|
||||
it('displays roadblock for a different plan of the same product with no upgrade path', async () => {
|
||||
const apiMocks = initSubscribedApiMocks({ planId: 'nextlevel' });
|
||||
const { findByTestId } = render(
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
planId: 'nextlevel',
|
||||
|
@ -574,7 +574,7 @@ describe('routes/Product', () => {
|
|||
planId: 'nextlevel',
|
||||
planEligibility: 'blocked_iap',
|
||||
});
|
||||
const { findByTestId } = render(
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
planId: 'nextlevel',
|
||||
|
@ -594,7 +594,9 @@ describe('routes/Product', () => {
|
|||
|
||||
it('displays payment confirmation if user is already subscribed to the product', async () => {
|
||||
const apiMocks = initSubscribedApiMocks();
|
||||
const { findByTestId, queryByTestId } = render(<Subject />);
|
||||
const { findByTestId, queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
await waitForElementToBeRemoved(queryByTestId('loading-overlay'));
|
||||
const confirmEl = await findByTestId('payment-confirmation');
|
||||
expect(confirmEl).toBeInTheDocument();
|
||||
|
@ -604,7 +606,7 @@ describe('routes/Product', () => {
|
|||
it('redirects to content server when there is no access token', async () => {
|
||||
const navigateToUrl = jest.fn();
|
||||
const appContext = { ...defaultAppContextValue(), accessToken: undefined };
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
productId="fizz"
|
||||
planId="quux"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { screen, render, cleanup, fireEvent } from '@testing-library/react';
|
||||
import { screen, cleanup, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import ActionButton, { ActionButtonProps } from './ActionButton';
|
||||
|
@ -10,6 +10,7 @@ import {
|
|||
PAYPAL_PAYMENT_ERROR_FUNDING_SOURCE,
|
||||
PAYPAL_PAYMENT_ERROR_MISSING_AGREEMENT,
|
||||
} from 'fxa-shared/subscriptions/types';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
|
||||
const { apiUrl } = defaultConfig().paypal;
|
||||
|
||||
|
@ -40,7 +41,9 @@ describe('routes/Subscriptions/ActionButton', () => {
|
|||
|
||||
it('renders revealonclick button when payment_provider is "stripe"', async () => {
|
||||
const onRevealUpdateClick = jest.fn();
|
||||
render(<Subject onRevealUpdateClick={onRevealUpdateClick} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject onRevealUpdateClick={onRevealUpdateClick} />
|
||||
);
|
||||
const revealButton = screen.getByTestId('reveal-payment-update-button');
|
||||
expect(revealButton).toBeInTheDocument();
|
||||
fireEvent.click(revealButton);
|
||||
|
@ -48,7 +51,7 @@ describe('routes/Subscriptions/ActionButton', () => {
|
|||
});
|
||||
|
||||
it('renders paypalActionButton when paypal is payment provider and paypal_payment_error is not set', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customer={{
|
||||
...CUSTOMER,
|
||||
|
@ -64,7 +67,7 @@ describe('routes/Subscriptions/ActionButton', () => {
|
|||
});
|
||||
|
||||
it('renders paypalFundingSourceActionButton when paypal is payment provider and paypal_payment_error is set to "funding_source"', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customer={{
|
||||
...CUSTOMER,
|
||||
|
@ -82,7 +85,7 @@ describe('routes/Subscriptions/ActionButton', () => {
|
|||
|
||||
it('renders paypalMissingAgreementActionButton when paypal is payment provider and paypal_payment_error is set to "missing_agreement"', async () => {
|
||||
const revealFixPaymentModal = jest.fn();
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
revealFixPaymentModal={revealFixPaymentModal}
|
||||
customer={{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { screen, render, act, fireEvent } from '@testing-library/react';
|
||||
import { screen, act, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import waitForExpect from 'wait-for-expect';
|
||||
import * as Amplitude from '../../../lib/amplitude';
|
||||
|
@ -21,6 +21,7 @@ import {
|
|||
INVOICE_WITH_TAX_INCLUSIVE_DISCOUNT,
|
||||
INVOICE_WITH_TAX_EXCLUSIVE_DISCOUNT,
|
||||
INVOICE_WITH_ZERO_TAX_EXCLUSIVE,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../../lib/test-utils';
|
||||
import { Plan } from 'fxa-payments-server/src/store/types';
|
||||
import {
|
||||
|
@ -71,7 +72,9 @@ describe('CancelSubscriptionPanel', () => {
|
|||
})) {
|
||||
describe(`when plan has ${k} interval`, () => {
|
||||
const runTests = (props: CancelSubscriptionPanelProps) => {
|
||||
render(<CancelSubscriptionPanel {...props} />);
|
||||
renderWithLocalizationProvider(
|
||||
<CancelSubscriptionPanel {...props} />
|
||||
);
|
||||
|
||||
const planPrice = formatPlanPricing(
|
||||
props.invoice.total,
|
||||
|
@ -131,7 +134,9 @@ describe('CancelSubscriptionPanel', () => {
|
|||
|
||||
it('should not be displayed when upgradeCTA is not in the plan', () => {
|
||||
const plan = findMockPlan('plan_daily');
|
||||
render(<CancelSubscriptionPanel {...baseProps} plan={plan} />);
|
||||
renderWithLocalizationProvider(
|
||||
<CancelSubscriptionPanel {...baseProps} plan={plan} />
|
||||
);
|
||||
expect(queryByTestId('upgrade-cta')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
@ -143,7 +148,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
upgradeCTA: 'Upgrade to the ultra super premium plus plan!',
|
||||
},
|
||||
};
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<CancelSubscriptionPanel {...baseProps} plan={upgradeablePlan} />
|
||||
);
|
||||
expect(queryByTestId('upgrade-cta')).toBeInTheDocument();
|
||||
|
@ -178,7 +183,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
},
|
||||
},
|
||||
};
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<CancelSubscriptionPanel {...baseProps} plan={upgradeablePlan} />
|
||||
);
|
||||
expect(queryByTestId('upgrade-cta')).toBeInTheDocument();
|
||||
|
@ -219,7 +224,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
},
|
||||
},
|
||||
};
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<AppContext.Provider
|
||||
value={{ ...defaultAppContext, navigatorLanguages: ['fr'] }}
|
||||
>
|
||||
|
@ -247,7 +252,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
'payment-cancel-btn = blee',
|
||||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = findMockPlan('plan_daily');
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel
|
||||
{...baseProps}
|
||||
|
@ -274,7 +279,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = { ...findMockPlan('plan_daily'), interval_count: 8 };
|
||||
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel {...baseProps} plan={plan} />
|
||||
</LocalizationProvider>
|
||||
|
@ -294,7 +299,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
`sub-next-bill-tax = Your next bill of { $priceAmount } + { $taxAmount } taxes is due due <strong>{ $date }</strong>`,
|
||||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = findMockPlan('plan_daily');
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel
|
||||
{...baseProps}
|
||||
|
@ -328,7 +333,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = { ...findMockPlan('plan_daily'), interval_count: 8 };
|
||||
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel
|
||||
{...baseProps}
|
||||
|
@ -357,7 +362,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = { ...findMockPlan('plan_daily'), interval_count: 8 };
|
||||
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel
|
||||
{...baseProps}
|
||||
|
@ -388,7 +393,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
`sub-next-bill-no-tax = Your next bill of { $priceAmount } prices is due due <strong>{ $date }</strong>`,
|
||||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = findMockPlan('plan_daily');
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel
|
||||
{...baseProps}
|
||||
|
@ -421,7 +426,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
`sub-next-bill-no-tax = Your next bill of { $priceAmount } prices is due due <strong>{ $date }</strong>`,
|
||||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = findMockPlan('plan_daily');
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel
|
||||
{...baseProps}
|
||||
|
@ -454,7 +459,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = { ...findMockPlan('plan_daily'), interval_count: 8 };
|
||||
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel
|
||||
{...baseProps}
|
||||
|
@ -483,7 +488,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = { ...findMockPlan('plan_daily'), interval_count: 8 };
|
||||
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel
|
||||
{...baseProps}
|
||||
|
@ -512,7 +517,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
'sub-item-stay-sub = haha never mind',
|
||||
].forEach((x) => bundle.addResource(new FluentResource(x)));
|
||||
const plan = findMockPlan('plan_daily');
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<LocalizationProvider l10n={new ReactLocalization([bundle])}>
|
||||
<CancelSubscriptionPanel {...baseProps} plan={plan} />
|
||||
</LocalizationProvider>
|
||||
|
@ -537,7 +542,9 @@ describe('CancelSubscriptionPanel', () => {
|
|||
describe('event handling', () => {
|
||||
beforeEach(() => {
|
||||
const plan = findMockPlan('plan_daily');
|
||||
render(<CancelSubscriptionPanel {...baseProps} plan={plan} />);
|
||||
renderWithLocalizationProvider(
|
||||
<CancelSubscriptionPanel {...baseProps} plan={plan} />
|
||||
);
|
||||
});
|
||||
|
||||
it('closes the cancellation confirmation on Stay Subscribed', () => {
|
||||
|
@ -566,7 +573,7 @@ describe('CancelSubscriptionPanel', () => {
|
|||
(Amplitude.cancelSubscriptionMounted as jest.Mock).mockClear();
|
||||
(Amplitude.cancelSubscriptionEngaged as jest.Mock).mockClear();
|
||||
const plan = findMockPlan('plan_daily');
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<CancelSubscriptionPanel
|
||||
{...baseProps}
|
||||
plan={plan}
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
screen,
|
||||
render,
|
||||
cleanup,
|
||||
act,
|
||||
fireEvent,
|
||||
} from '@testing-library/react';
|
||||
import { screen, cleanup, act, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import waitForExpect from 'wait-for-expect';
|
||||
|
@ -16,6 +10,7 @@ import {
|
|||
mockStripeElementOnChangeFns,
|
||||
elementChangeResponse,
|
||||
MOCK_PAYPAL_CUSTOMER_RESULT,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
import {
|
||||
CUSTOMER,
|
||||
|
@ -118,41 +113,45 @@ describe('routes/Subscriptions/PaymentUpdateFormV2', () => {
|
|||
});
|
||||
|
||||
it('renders with payment update form hidden initially', async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
expect(screen.queryByTestId('payment-update')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('paymentForm')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders valid expiration date', async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
expect(screen.queryByTestId('card-expiration-date')).toHaveTextContent(
|
||||
'Expires February 2099'
|
||||
);
|
||||
});
|
||||
|
||||
it('does not render expiration date if date is invalid', async () => {
|
||||
render(<Subject customer={{ ...CUSTOMER, exp_month: undefined }} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject customer={{ ...CUSTOMER, exp_month: undefined }} />
|
||||
);
|
||||
expect(
|
||||
screen.queryByTestId('card-expiration-date')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('reveals the payment update form on clicking Change button', async () => {
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
expect(screen.queryByTestId('payment-update')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByTestId('change-button'));
|
||||
expect(screen.queryByTestId('paymentForm')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders correctly for paypal', async () => {
|
||||
render(<Subject customer={{ ...CUSTOMER, payment_provider: 'paypal' }} />);
|
||||
renderWithLocalizationProvider(
|
||||
<Subject customer={{ ...CUSTOMER, payment_provider: 'paypal' }} />
|
||||
);
|
||||
expect(
|
||||
screen.getByTestId('change-payment-update-button')?.getAttribute('href')
|
||||
).toEqual(`${apiUrl}/myaccount/autopay/connect/ba-131243`);
|
||||
});
|
||||
|
||||
it('renders correctly for paypal with archived plan', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customer={{ ...CUSTOMER, payment_provider: 'paypal' }}
|
||||
plan={INACTIVE_PLAN}
|
||||
|
@ -173,7 +172,7 @@ describe('routes/Subscriptions/PaymentUpdateFormV2', () => {
|
|||
|
||||
const refreshSubscriptions = jest.fn();
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
customer: {
|
||||
|
@ -228,7 +227,7 @@ describe('routes/Subscriptions/PaymentUpdateFormV2', () => {
|
|||
const refreshSubscriptions = jest.fn();
|
||||
|
||||
await act(async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
customer: {
|
||||
|
@ -273,7 +272,7 @@ describe('routes/Subscriptions/PaymentUpdateFormV2', () => {
|
|||
});
|
||||
|
||||
it('renders correctly for incorrect funding source for paypal', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customer={{
|
||||
...CUSTOMER,
|
||||
|
@ -295,7 +294,7 @@ describe('routes/Subscriptions/PaymentUpdateFormV2', () => {
|
|||
refreshSubscriptions = jest.fn(),
|
||||
...props
|
||||
} = {}) {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
{...{
|
||||
apiClientOverrides,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { render } from '@testing-library/react';
|
||||
import { IapSubscription } from 'fxa-shared/subscriptions/types';
|
||||
|
||||
import { SignInLayout } from '../../../components/AppLayout';
|
||||
|
@ -9,7 +8,11 @@ import {
|
|||
IAP_GOOGLE_SUBSCRIPTION,
|
||||
SELECTED_PLAN,
|
||||
} from '../../../lib/mock-data';
|
||||
import { deepCopy, MockApp } from '../../../lib/test-utils';
|
||||
import {
|
||||
deepCopy,
|
||||
MockApp,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../../lib/test-utils';
|
||||
import { PickPartial } from '../../../lib/types';
|
||||
import SubscriptionIapItem, {
|
||||
SubscriptionIapItemProps,
|
||||
|
@ -40,7 +43,7 @@ const Subject = ({
|
|||
|
||||
describe('routes/Subscriptions/SubscriptionIapItem', () => {
|
||||
it('renders as expected for a Google Play subscription with autorenew=true', async () => {
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
const subscriptionItemEle = await findByTestId('subscription-item');
|
||||
expect(subscriptionItemEle).toBeInTheDocument();
|
||||
const iapDetailsEle = await findByTestId('iap-details');
|
||||
|
@ -51,7 +54,7 @@ describe('routes/Subscriptions/SubscriptionIapItem', () => {
|
|||
expect(manageButton).toBeInTheDocument();
|
||||
});
|
||||
it('renders as expected for a Google Play subscription with autorenew=false', async () => {
|
||||
const { findByTestId } = render(
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customerSubscription={
|
||||
{
|
||||
|
@ -67,7 +70,7 @@ describe('routes/Subscriptions/SubscriptionIapItem', () => {
|
|||
expect(iapDetailsEle).toHaveTextContent('Expires on');
|
||||
});
|
||||
it('renders as expected for an App Store subscription', async () => {
|
||||
const { findByTestId, queryByTestId } = render(
|
||||
const { findByTestId, queryByTestId } = renderWithLocalizationProvider(
|
||||
<Subject
|
||||
customerSubscription={IAP_APPLE_SUBSCRIPTION as IapSubscription}
|
||||
/>
|
||||
|
@ -84,7 +87,7 @@ describe('routes/Subscriptions/SubscriptionIapItem', () => {
|
|||
it('renders an App store subscription with no expiration data', async () => {
|
||||
const subscription = deepCopy(IAP_APPLE_SUBSCRIPTION);
|
||||
|
||||
const { findByTestId } = render(
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject customerSubscription={subscription as IapSubscription} />
|
||||
);
|
||||
const subscriptionItemEle = await findByTestId('subscription-item');
|
||||
|
@ -100,7 +103,7 @@ describe('routes/Subscriptions/SubscriptionIapItem', () => {
|
|||
subscription.expiry_time_millis = 1656759852811;
|
||||
subscription.auto_renewing = true;
|
||||
|
||||
const { findByTestId } = render(
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject customerSubscription={subscription as IapSubscription} />
|
||||
);
|
||||
const subscriptionItemEle = await findByTestId('subscription-item');
|
||||
|
@ -117,7 +120,7 @@ describe('routes/Subscriptions/SubscriptionIapItem', () => {
|
|||
subscription.expiry_time_millis = 1656759852811;
|
||||
subscription.auto_renewing = false;
|
||||
|
||||
const { findByTestId } = render(
|
||||
const { findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject customerSubscription={subscription as IapSubscription} />
|
||||
);
|
||||
const subscriptionItemEle = await findByTestId('subscription-item');
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
import {
|
||||
render,
|
||||
cleanup,
|
||||
fireEvent,
|
||||
RenderResult,
|
||||
|
@ -44,6 +43,7 @@ import {
|
|||
MOCK_LATEST_INVOICE_ITEMS,
|
||||
MOCK_CUSTOMER_ARCHIVED_PLAN,
|
||||
MOCK_ACTIVE_SUBSCRIPTIONS_TO_ARCHIVED,
|
||||
renderWithLocalizationProvider,
|
||||
} from '../../lib/test-utils';
|
||||
|
||||
import { SettingsLayout } from '../../components/AppLayout';
|
||||
|
@ -171,7 +171,7 @@ describe('routes/Subscriptions', () => {
|
|||
mockCustomer: MOCK_CUSTOMER_AFTER_SUBSCRIPTION,
|
||||
mockActiveSubscriptions: MOCK_ACTIVE_SUBSCRIPTIONS_AFTER_SUBSCRIPTION,
|
||||
});
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
await screen.findByTestId('subscription-management-loaded');
|
||||
await waitForExpect(() => {
|
||||
expect(screen.queryByTestId('loading-overlay')).not.toBeInTheDocument();
|
||||
|
@ -188,9 +188,8 @@ describe('routes/Subscriptions', () => {
|
|||
mockCustomer: MOCK_CUSTOMER_AFTER_SUBSCRIPTION,
|
||||
});
|
||||
|
||||
const { findByTestId, queryAllByTestId, queryByTestId } = render(
|
||||
<Subject />
|
||||
);
|
||||
const { findByTestId, queryAllByTestId, queryByTestId } =
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
if (window.onload) {
|
||||
dispatchEvent(new Event('load'));
|
||||
}
|
||||
|
@ -206,7 +205,7 @@ describe('routes/Subscriptions', () => {
|
|||
initApiMocks({
|
||||
mockCustomer: MOCK_CUSTOMER_AFTER_SUBSCRIPTION,
|
||||
});
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
await findByTestId('manage-pocket-title');
|
||||
await findByTestId('manage-pocket-link');
|
||||
});
|
||||
|
@ -227,7 +226,9 @@ describe('routes/Subscriptions', () => {
|
|||
},
|
||||
})),
|
||||
});
|
||||
const { findByTestId, queryAllByTestId } = render(<Subject />);
|
||||
const { findByTestId, queryAllByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
await findByTestId('subscription-management-loaded');
|
||||
expect(queryAllByTestId('upgrade-cta').length).toBe(2);
|
||||
// Ensure that our HTML in upgradeCTA got rendered as markup
|
||||
|
@ -237,7 +238,7 @@ describe('routes/Subscriptions', () => {
|
|||
it('offers a button for support', async () => {
|
||||
initApiMocks();
|
||||
const navigateToUrl = jest.fn();
|
||||
const { getByTestId, findByTestId } = render(
|
||||
const { getByTestId, findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject navigateToUrl={navigateToUrl} />
|
||||
);
|
||||
await findByTestId('subscription-management-loaded');
|
||||
|
@ -251,7 +252,9 @@ describe('routes/Subscriptions', () => {
|
|||
mockCustomer: MOCK_CUSTOMER_AFTER_SUBSCRIPTION,
|
||||
mockActiveSubscriptions: MOCK_ACTIVE_SUBSCRIPTIONS_AFTER_SUBSCRIPTION,
|
||||
});
|
||||
const { getAllByTestId, findByTestId } = render(<Subject />);
|
||||
const { getAllByTestId, findByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
await findByTestId('subscription-management-loaded');
|
||||
fireEvent.click(getAllByTestId('reveal-cancel-subscription-button')[0]);
|
||||
expect(manageSubscriptionsMounted).toBeCalledTimes(1);
|
||||
|
@ -260,7 +263,7 @@ describe('routes/Subscriptions', () => {
|
|||
|
||||
it('displays profile displayName if available', async () => {
|
||||
initApiMocks({ displayName: 'Foo Barson' });
|
||||
const { findByText } = render(<Subject />);
|
||||
const { findByText } = renderWithLocalizationProvider(<Subject />);
|
||||
await findByText('Foo Barson');
|
||||
});
|
||||
|
||||
|
@ -271,7 +274,7 @@ describe('routes/Subscriptions', () => {
|
|||
});
|
||||
|
||||
const navigateToUrl = jest.fn();
|
||||
render(<Subject navigateToUrl={navigateToUrl} />);
|
||||
renderWithLocalizationProvider(<Subject navigateToUrl={navigateToUrl} />);
|
||||
|
||||
await waitForExpect(() => expect(navigateToUrl).toBeCalled());
|
||||
expect(navigateToUrl).toBeCalledWith(`${contentServer}/settings`);
|
||||
|
@ -291,7 +294,7 @@ describe('routes/Subscriptions', () => {
|
|||
nock(authServer)
|
||||
.get('/v1/oauth/subscriptions/invoice/preview-subsequent')
|
||||
.reply(200, MOCK_SUBSEQUENT_INVOICES);
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
await findByTestId('error-loading-profile');
|
||||
});
|
||||
|
||||
|
@ -309,7 +312,7 @@ describe('routes/Subscriptions', () => {
|
|||
nock(authServer)
|
||||
.get('/v1/oauth/subscriptions/invoice/preview-subsequent')
|
||||
.reply(200, MOCK_SUBSEQUENT_INVOICES);
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
await findByTestId('error-loading-plans');
|
||||
});
|
||||
|
||||
|
@ -327,7 +330,7 @@ describe('routes/Subscriptions', () => {
|
|||
nock(authServer)
|
||||
.get('/v1/oauth/subscriptions/invoice/preview-subsequent')
|
||||
.reply(200, MOCK_SUBSEQUENT_INVOICES);
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
await findByTestId('error-loading-customer');
|
||||
});
|
||||
|
||||
|
@ -345,7 +348,7 @@ describe('routes/Subscriptions', () => {
|
|||
nock(authServer)
|
||||
.get('/v1/oauth/subscriptions/invoice/preview-subsequent')
|
||||
.reply(500, MOCK_SUBSEQUENT_INVOICES);
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
await findByTestId('error-loading-invoice');
|
||||
});
|
||||
|
||||
|
@ -363,7 +366,7 @@ describe('routes/Subscriptions', () => {
|
|||
nock(authServer)
|
||||
.get('/v1/oauth/subscriptions/invoice/preview-subsequent')
|
||||
.reply(200, []);
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
await findByTestId('error-subhub-missing-subsequent-invoice');
|
||||
});
|
||||
|
||||
|
@ -385,7 +388,7 @@ describe('routes/Subscriptions', () => {
|
|||
.reply(200, MOCK_SUBSEQUENT_INVOICES);
|
||||
|
||||
const navigateToUrl = jest.fn();
|
||||
render(<Subject navigateToUrl={navigateToUrl} />);
|
||||
renderWithLocalizationProvider(<Subject navigateToUrl={navigateToUrl} />);
|
||||
|
||||
await waitForExpect(() => expect(navigateToUrl).toBeCalled());
|
||||
expect(navigateToUrl).toBeCalledWith(`${contentServer}/settings`);
|
||||
|
@ -398,7 +401,8 @@ describe('routes/Subscriptions', () => {
|
|||
.delete('/v1/oauth/subscriptions/active/sub0.28964929339372136')
|
||||
.reply(400, {});
|
||||
|
||||
const { findByTestId, queryAllByTestId, getByTestId } = render(<Subject />);
|
||||
const { findByTestId, queryAllByTestId, getByTestId } =
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
// Wait for the page to load with one subscription
|
||||
await findByTestId('subscription-management-loaded');
|
||||
|
@ -428,7 +432,7 @@ describe('routes/Subscriptions', () => {
|
|||
queryByTestId,
|
||||
getByTestId,
|
||||
getAllByTestId,
|
||||
} = render(<Subject />);
|
||||
} = renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
// Wait for the page to load with one subscription
|
||||
await findByTestId('subscription-management-loaded');
|
||||
|
@ -585,7 +589,7 @@ describe('routes/Subscriptions', () => {
|
|||
});
|
||||
|
||||
const { findByTestId, queryAllByTestId, queryByTestId, getAllByTestId } =
|
||||
render(<Subject />);
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
// Wait for the page to load with one subscription
|
||||
await findByTestId('subscription-management-loaded');
|
||||
|
@ -810,9 +814,8 @@ describe('routes/Subscriptions', () => {
|
|||
nock(authServer)
|
||||
.get('/v1/oauth/subscriptions/invoice/preview-subsequent')
|
||||
.reply(200, MOCK_SUBSEQUENT_INVOICES);
|
||||
const { findByTestId, getByTestId, getByAltText, queryByTestId } = render(
|
||||
<Subject />
|
||||
);
|
||||
const { findByTestId, getByTestId, getByAltText, queryByTestId } =
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
// Wait for the page to load with one subscription
|
||||
await findByTestId('subscription-management-loaded');
|
||||
|
@ -857,7 +860,9 @@ describe('routes/Subscriptions', () => {
|
|||
.get('/v1/oauth/subscriptions/invoice/preview-subsequent')
|
||||
.reply(200, MOCK_SUBSEQUENT_INVOICES);
|
||||
|
||||
const { findByTestId, getByTestId } = render(<Subject />);
|
||||
const { findByTestId, getByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
|
||||
// Wait for the page to load with one subscription
|
||||
await findByTestId('subscription-management-loaded');
|
||||
|
@ -902,7 +907,7 @@ describe('routes/Subscriptions', () => {
|
|||
nock(authServer)
|
||||
.get('/v1/oauth/subscriptions/invoice/preview-subsequent')
|
||||
.reply(200, MOCK_SUBSEQUENT_INVOICES);
|
||||
const { findByTestId } = render(<Subject />);
|
||||
const { findByTestId } = renderWithLocalizationProvider(<Subject />);
|
||||
await findByTestId('error-subhub-missing-plan');
|
||||
});
|
||||
|
||||
|
@ -916,7 +921,7 @@ describe('routes/Subscriptions', () => {
|
|||
Object.defineProperty(window.location, 'href', { set: setSpy });
|
||||
|
||||
const appContext = { accessToken: undefined };
|
||||
render(<Subject appContext={appContext} />);
|
||||
renderWithLocalizationProvider(<Subject appContext={appContext} />);
|
||||
|
||||
expect(setSpy).toHaveBeenCalledWith(
|
||||
'https://content.example/subscriptions'
|
||||
|
@ -968,9 +973,8 @@ describe('routes/Subscriptions', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const { findByTestId, queryAllByTestId, queryByTestId } = render(
|
||||
<Subject />
|
||||
);
|
||||
const { findByTestId, queryAllByTestId, queryByTestId } =
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
await findByTestId('subscription-management-loaded');
|
||||
|
||||
|
@ -995,7 +999,9 @@ describe('routes/Subscriptions', () => {
|
|||
mockSubsequentInvoices: MOCK_SUBSEQUENT_INVOICES,
|
||||
});
|
||||
|
||||
const { findByTestId, queryAllByTestId } = render(<Subject />);
|
||||
const { findByTestId, queryAllByTestId } = renderWithLocalizationProvider(
|
||||
<Subject />
|
||||
);
|
||||
|
||||
await findByTestId('subscription-management-loaded');
|
||||
|
||||
|
|
|
@ -4,16 +4,20 @@
|
|||
|
||||
module.exports = {
|
||||
stories: ['../**/*.stories.tsx'],
|
||||
core: {
|
||||
builder: 'webpack5',
|
||||
},
|
||||
addons: [
|
||||
'@storybook/addon-actions',
|
||||
'@storybook/addon-links',
|
||||
{
|
||||
name: '@storybook/addon-postcss',
|
||||
options: {
|
||||
postcssLoaderOptions: {
|
||||
implementation: require('postcss'),
|
||||
},
|
||||
},
|
||||
},
|
||||
'@storybook/addon-styling',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-webpack5',
|
||||
options: {},
|
||||
},
|
||||
features: { storyStoreV7: false },
|
||||
docs: {
|
||||
autodocs: true,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import AppErrorBoundary from '.';
|
||||
import { renderWithLocalizationProvider } from '../../lib/test-utils/localizationProvider';
|
||||
|
||||
window.console.error = jest.fn();
|
||||
|
||||
|
@ -12,7 +13,7 @@ describe('AppErrorBoundary', () => {
|
|||
it('renders children that do not cause exceptions', () => {
|
||||
const GoodComponent = () => <p data-testid="good-component">Hi</p>;
|
||||
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<AppErrorBoundary>
|
||||
<GoodComponent />
|
||||
</AppErrorBoundary>
|
||||
|
@ -26,7 +27,7 @@ describe('AppErrorBoundary', () => {
|
|||
throw new Error('bad');
|
||||
};
|
||||
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<AppErrorBoundary>
|
||||
<BadComponent />
|
||||
</AppErrorBoundary>
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import AppErrorDialog from './index';
|
||||
import AppLocalizationProvider from '../../lib/AppLocalizationProvider';
|
||||
|
||||
storiesOf('Components/AppErrorDialog', module).add('basic', () => (
|
||||
<AppErrorDialog error={new Error('Uh oh!')} />
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<AppErrorDialog error={new Error('Uh oh!')} />
|
||||
</AppLocalizationProvider>
|
||||
));
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import AppErrorDialog from '.';
|
||||
import { renderWithLocalizationProvider } from '../../lib/test-utils/localizationProvider';
|
||||
|
||||
describe('AppErrorDialog', () => {
|
||||
it('renders a general error dialog', () => {
|
||||
const { queryByTestId } = render(
|
||||
const { queryByTestId } = renderWithLocalizationProvider(
|
||||
<AppErrorDialog error={new Error('bad')} />
|
||||
);
|
||||
|
||||
|
|
|
@ -5,5 +5,13 @@
|
|||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { Footer } from './index';
|
||||
import AppLocalizationProvider from '../../lib/AppLocalizationProvider';
|
||||
|
||||
storiesOf('Components/Footer', module).add('default', () => <Footer />);
|
||||
storiesOf('Components/Footer', module).add('default', () => (
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<Footer />
|
||||
</AppLocalizationProvider>
|
||||
));
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import Footer from '.';
|
||||
import { renderWithLocalizationProvider } from '../../lib/test-utils/localizationProvider';
|
||||
|
||||
describe('Footer', () => {
|
||||
it('renders as expected', () => {
|
||||
render(<Footer />);
|
||||
renderWithLocalizationProvider(<Footer />);
|
||||
|
||||
const linkMozilla = screen.getByTestId('link-mozilla');
|
||||
|
||||
|
|
|
@ -5,7 +5,22 @@
|
|||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import Head from './index';
|
||||
import AppLocalizationProvider from '../../lib/AppLocalizationProvider';
|
||||
|
||||
storiesOf('Components/Head', module)
|
||||
.add('basic', () => <Head />)
|
||||
.add('with title', () => <Head title="neat feature" />);
|
||||
.add('basic', () => (
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<Head />
|
||||
</AppLocalizationProvider>
|
||||
))
|
||||
.add('with title', () => (
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<Head title="neat feature" />
|
||||
</AppLocalizationProvider>
|
||||
));
|
||||
|
|
|
@ -2,14 +2,25 @@ import React from 'react';
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import { Header } from './index';
|
||||
import { LogoLockup } from '../LogoLockup';
|
||||
import AppLocalizationProvider from '../../lib/AppLocalizationProvider';
|
||||
|
||||
storiesOf('Components/Header', module)
|
||||
.add('basic', () => (
|
||||
<Header left={<div>left content</div>} right={<div>right content</div>} />
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<Header left={<div>left content</div>} right={<div>right content</div>} />
|
||||
</AppLocalizationProvider>
|
||||
))
|
||||
.add('with LogoLockup', () => (
|
||||
<Header
|
||||
left={<LogoLockup>Some title</LogoLockup>}
|
||||
right={<div>right content</div>}
|
||||
/>
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<Header
|
||||
left={<LogoLockup>Some title</LogoLockup>}
|
||||
right={<div>right content</div>}
|
||||
/>
|
||||
</AppLocalizationProvider>
|
||||
));
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import LinkExternal from './index';
|
||||
import AppLocalizationProvider from '../../lib/AppLocalizationProvider';
|
||||
|
||||
storiesOf('Components/LinkExternal', module).add('basic', () => (
|
||||
<LinkExternal href="https://mozilla.org">
|
||||
Keep the internet open and accessible to all.
|
||||
</LinkExternal>
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<LinkExternal href="https://mozilla.org">
|
||||
Keep the internet open and accessible to all.
|
||||
</LinkExternal>
|
||||
</AppLocalizationProvider>
|
||||
));
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import LinkExternal from './index';
|
||||
import { renderWithLocalizationProvider } from '../../lib/test-utils/localizationProvider';
|
||||
|
||||
it('renders without imploding', () => {
|
||||
const className = 'mozilla-link';
|
||||
const href = 'https://mozilla.org/';
|
||||
const textContent = 'Keep the internet open and accessible to all.';
|
||||
|
||||
const renderResult = render(
|
||||
const renderResult = renderWithLocalizationProvider(
|
||||
<LinkExternal {...{ className, href }}>{textContent}</LinkExternal>
|
||||
);
|
||||
|
||||
|
|
|
@ -1,12 +1,32 @@
|
|||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import LoadingSpinner, { SpinnerType } from './index';
|
||||
import AppLocalizationProvider from '../../lib/AppLocalizationProvider';
|
||||
|
||||
storiesOf('Components/LoadingSpinner', module)
|
||||
.add('default', () => <LoadingSpinner />)
|
||||
.add('blue', () => <LoadingSpinner spinnerType={SpinnerType.Blue} />)
|
||||
.add('default', () => (
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<LoadingSpinner />
|
||||
</AppLocalizationProvider>
|
||||
))
|
||||
.add('blue', () => (
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<LoadingSpinner spinnerType={SpinnerType.Blue} />
|
||||
</AppLocalizationProvider>
|
||||
))
|
||||
.add('white', () => (
|
||||
<div className="bg-grey-700">
|
||||
<LoadingSpinner spinnerType={SpinnerType.White} />
|
||||
</div>
|
||||
<AppLocalizationProvider
|
||||
baseDir="./locales"
|
||||
userLocales={navigator.languages}
|
||||
>
|
||||
<div className="bg-grey-700">
|
||||
<LoadingSpinner spinnerType={SpinnerType.White} />
|
||||
</div>
|
||||
</AppLocalizationProvider>
|
||||
));
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { screen } from '@testing-library/react';
|
||||
|
||||
import { LoadingSpinner, SpinnerType } from './index';
|
||||
import { renderWithLocalizationProvider } from '../../lib/test-utils/localizationProvider';
|
||||
|
||||
it('renders defaults as expected', () => {
|
||||
render(<LoadingSpinner />);
|
||||
renderWithLocalizationProvider(<LoadingSpinner />);
|
||||
const result = screen.queryByTestId('loading-spinner');
|
||||
const spinnerType = screen.queryByTestId('loading-spinner-blue');
|
||||
expect(result).toBeInTheDocument();
|
||||
|
@ -12,7 +13,7 @@ it('renders defaults as expected', () => {
|
|||
});
|
||||
|
||||
it('renders with custom spinner classNames', () => {
|
||||
render(<LoadingSpinner imageClassName="testclass" />);
|
||||
renderWithLocalizationProvider(<LoadingSpinner imageClassName="testclass" />);
|
||||
const result = screen.queryByTestId('loading-spinner');
|
||||
const spinnerImage = screen.queryByTestId('loading-spinner-blue');
|
||||
expect(result).toBeInTheDocument();
|
||||
|
@ -20,7 +21,9 @@ it('renders with custom spinner classNames', () => {
|
|||
});
|
||||
|
||||
it('renders blue spinner as expected', () => {
|
||||
render(<LoadingSpinner spinnerType={SpinnerType.Blue} />);
|
||||
renderWithLocalizationProvider(
|
||||
<LoadingSpinner spinnerType={SpinnerType.Blue} />
|
||||
);
|
||||
const result = screen.queryByTestId('loading-spinner');
|
||||
const spinnerType = screen.queryByTestId('loading-spinner-blue');
|
||||
expect(result).toBeInTheDocument();
|
||||
|
@ -28,7 +31,9 @@ it('renders blue spinner as expected', () => {
|
|||
});
|
||||
|
||||
it('renders blue spinner as expected', () => {
|
||||
render(<LoadingSpinner spinnerType={SpinnerType.White} />);
|
||||
renderWithLocalizationProvider(
|
||||
<LoadingSpinner spinnerType={SpinnerType.White} />
|
||||
);
|
||||
const result = screen.queryByTestId('loading-spinner');
|
||||
const spinnerType = screen.queryByTestId('loading-spinner-white');
|
||||
expect(result).toBeInTheDocument();
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import LogoLockup from '.';
|
||||
import { renderWithLocalizationProvider } from '../../lib/test-utils/localizationProvider';
|
||||
|
||||
// TODO: functional test for `data-testid="logo-text"` to be
|
||||
// hidden at mobile
|
||||
|
||||
describe('LogoLockup', () => {
|
||||
it('renders as expected', () => {
|
||||
const { getByTestId } = render(<LogoLockup>Firefox account</LogoLockup>);
|
||||
const { getByTestId } = renderWithLocalizationProvider(
|
||||
<LogoLockup>Firefox account</LogoLockup>
|
||||
);
|
||||
expect(getByTestId('logo')).toBeInTheDocument();
|
||||
expect(getByTestId('logo-text').textContent).toContain('Firefox account');
|
||||
});
|
||||
|
|
|
@ -44,11 +44,11 @@ const permitAdditionalJSImports = (config) => {
|
|||
if (
|
||||
config.module.rules[1] &&
|
||||
config.module.rules[1].oneOf &&
|
||||
config.module.rules[1].oneOf[2].test.toString() ===
|
||||
config.module.rules[1].oneOf[3].test.toString() ===
|
||||
'/\\.(js|mjs|jsx|ts|tsx)$/'
|
||||
) {
|
||||
config.module.rules[1].oneOf[2].include = [
|
||||
config.module.rules[1].oneOf[2].include,
|
||||
config.module.rules[1].oneOf[3].include = [
|
||||
config.module.rules[1].oneOf[3].include,
|
||||
allFxa,
|
||||
];
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,7 @@ const customizeWebpackConfig = ({ config }) => ({
|
|||
...config,
|
||||
resolve: {
|
||||
...config.resolve,
|
||||
plugins: config.resolve.plugins.map((plugin) => {
|
||||
plugins: (config.resolve.plugins || []).map((plugin) => {
|
||||
// Rebuild ModuleScopePlugin with some additional allowed paths
|
||||
if (
|
||||
plugin.constructor &&
|
||||
|
@ -28,7 +28,7 @@ const customizeWebpackConfig = ({ config }) => ({
|
|||
// Register a few more extensions to resolve
|
||||
extensions: [...config.resolve.extensions, '.svg', '.scss', '.css', '.png'],
|
||||
// Add aliases to some packages shared across the project
|
||||
alias: { ...config.alias, ...additionalJSImports },
|
||||
alias: { ...config.resolve.alias, ...additionalJSImports },
|
||||
},
|
||||
module: {
|
||||
...config.module,
|
||||
|
@ -43,6 +43,8 @@ const customizeWebpackConfig = ({ config }) => ({
|
|||
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||
},
|
||||
// Support using SVGs as React components
|
||||
// fxa-react stories need this since that package does not have the
|
||||
// webpack config from CRA that includes svgr
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
|
@ -50,9 +52,17 @@ const customizeWebpackConfig = ({ config }) => ({
|
|||
loader: require.resolve('@svgr/webpack'),
|
||||
options: {
|
||||
svgoConfig: {
|
||||
plugins: {
|
||||
removeViewBox: false,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
// disable plugins
|
||||
removeViewBox: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -46,11 +46,18 @@ async function createFluentBundleGenerator(
|
|||
|
||||
const mergedBundle = fetched.reduce((obj, cur) => Object.assign(obj, cur));
|
||||
|
||||
return getBundleGenerator(currentLocales, mergedBundle);
|
||||
}
|
||||
|
||||
function getBundleGenerator(
|
||||
locales: string[],
|
||||
messages: { [key: string]: string[] }
|
||||
) {
|
||||
return function* generateFluentBundles() {
|
||||
for (const locale of currentLocales) {
|
||||
for (const locale of locales) {
|
||||
const sourceLocale = EN_GB_LOCALES.includes(locale) ? 'en-GB' : locale;
|
||||
const cx = new FluentBundle(locale);
|
||||
for (const i of mergedBundle[sourceLocale]) {
|
||||
for (const i of messages[sourceLocale]) {
|
||||
const resource = new FluentResource(i);
|
||||
cx.addResource(resource);
|
||||
}
|
||||
|
@ -71,6 +78,8 @@ type Props = {
|
|||
userLocales: ReadonlyArray<string>;
|
||||
bundles: Array<string>;
|
||||
children: any;
|
||||
// pass messages directly in, used in testing
|
||||
messages?: { [key: string]: string[] };
|
||||
};
|
||||
|
||||
export default class AppLocalizationProvider extends Component<Props, State> {
|
||||
|
@ -93,10 +102,20 @@ export default class AppLocalizationProvider extends Component<Props, State> {
|
|||
}
|
||||
|
||||
async componentDidMount() {
|
||||
if (this.props.messages) {
|
||||
this.setState({
|
||||
l10n: new ReactLocalization(
|
||||
getBundleGenerator(
|
||||
Object.keys(this.props.messages),
|
||||
this.props.messages
|
||||
)()
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const { baseDir, userLocales, bundles } = this.state;
|
||||
|
||||
const currentLocales = parseAcceptLanguage(userLocales.join(', '));
|
||||
|
||||
const bundleGenerator = await createFluentBundleGenerator(
|
||||
baseDir,
|
||||
currentLocales,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { DecoratorFn } from '@storybook/react';
|
||||
import AppLocalizationProvider from 'fxa-react/lib/AppLocalizationProvider';
|
||||
import AppLocalizationProvider from './AppLocalizationProvider';
|
||||
|
||||
// This decorator makes the localization bundles available in the stories.
|
||||
// If a localized string is available, that will be rendered in the storybook,
|
|
@ -0,0 +1,25 @@
|
|||
import { render } from '@testing-library/react';
|
||||
import AppLocalizationProvider from 'fxa-react/lib/AppLocalizationProvider';
|
||||
|
||||
export function renderWithLocalizationProvider(
|
||||
children: JSX.Element,
|
||||
messages = { en: ['testo: lol'] }
|
||||
): ReturnType<typeof render> {
|
||||
// by default fluent warns about missing messages, but there's no way to
|
||||
// disable it right now. see
|
||||
// https://github.com/projectfluent/fluent.js/issues/411
|
||||
return render(withLocalizationProvider(children, messages));
|
||||
}
|
||||
|
||||
export function withLocalizationProvider(
|
||||
children: JSX.Element,
|
||||
messages = { en: ['testo: lol'] }
|
||||
) {
|
||||
return (
|
||||
<AppLocalizationProvider messages={messages}>
|
||||
{children}
|
||||
</AppLocalizationProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default { renderWithLocalizationProvider, withLocalizationProvider };
|
|
@ -4,7 +4,12 @@
|
|||
|
||||
import { FluentBundle, FluentDateTime, FluentVariable } from '@fluent/bundle';
|
||||
import { Message, Pattern } from '@fluent/bundle/esm/ast';
|
||||
import { Localized, LocalizedProps, ReactLocalization } from '@fluent/react';
|
||||
import {
|
||||
Localized,
|
||||
LocalizedProps,
|
||||
ReactLocalization,
|
||||
LocalizationProvider,
|
||||
} from '@fluent/react';
|
||||
import React from 'react';
|
||||
|
||||
// Going from react page to non-react page requires a hard navigate. This temporary
|
||||
|
|
|
@ -3,17 +3,17 @@
|
|||
"version": "0.0.0",
|
||||
"description": "Shared components for FxA React Apps",
|
||||
"exports": {
|
||||
"./components/": "./dist/packages/fxa-react/components/",
|
||||
"./components/": "./components/",
|
||||
"./configs/tailwind": "./configs/tailwind.js",
|
||||
"./configs/rescripts": "./configs/rescripts.js",
|
||||
"./configs/storybooks": "./configs/storybooks.js",
|
||||
"./images/": "./images/",
|
||||
"./extract-imported-components": "./extract-imported-components.js",
|
||||
"./lib/": "./dist/packages/fxa-react/lib/"
|
||||
"./lib/": "./lib/"
|
||||
},
|
||||
"scripts": {
|
||||
"build-css": "tailwindcss -i ./styles/tailwind.css -o ./styles/tailwind.out.css",
|
||||
"build-storybook": "yarn merge-ftl && NODE_ENV=production yarn build-css && NODE_OPTIONS=--openssl-legacy-provider build-storybook && cp -r public/locales ./storybook-static/locales",
|
||||
"build-storybook": "yarn merge-ftl && NODE_ENV=production yarn build-css && NODE_OPTIONS=--openssl-legacy-provider storybook build && cp -r public/locales ./storybook-static/locales",
|
||||
"build": "tsc --build && yarn merge-ftl",
|
||||
"compile": "tsc --noEmit",
|
||||
"clean": "git clean -fXd",
|
||||
|
@ -24,7 +24,7 @@
|
|||
"start": "yarn merge-ftl && pm2 start pm2.config.js",
|
||||
"stop": "pm2 stop pm2.config.js",
|
||||
"delete": "pm2 delete pm2.config.js",
|
||||
"storybook": "yarn merge-ftl && yarn build-css && NODE_OPTIONS=--openssl-legacy-provider start-storybook -p 6007 --no-version-updates",
|
||||
"storybook": "yarn merge-ftl && yarn build-css && NODE_OPTIONS=--openssl-legacy-provider storybook dev -p 6007 --no-version-updates",
|
||||
"test": "yarn merge-ftl-test && JEST_JUNIT_OUTPUT_FILE=../../artifacts/tests/$npm_package_name/jest-unit.xml jest --coverage --runInBand --logHeapUsage --env=jest-environment-jsdom -t '^(?!.*?#integration).*' --ci --reporters=default --reporters=jest-junit ",
|
||||
"test-unit": "yarn test",
|
||||
"test-integration": "echo No integration tests present for $npm_package_name",
|
||||
|
@ -35,7 +35,7 @@
|
|||
"dependencies": {
|
||||
"@fluent/bundle": "^0.18.0",
|
||||
"@fluent/langneg": "^0.6.2",
|
||||
"@fluent/react": "^0.13.1",
|
||||
"@fluent/react": "^0.14.1",
|
||||
"async-wait-until": "^2.0.12",
|
||||
"classnames": "^2.3.1",
|
||||
"fetch-mock": "^9.11.0",
|
||||
|
@ -50,16 +50,20 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@storybook/addon-actions": "^6.5.9",
|
||||
"@storybook/addon-links": "^6.5.9",
|
||||
"@storybook/addon-postcss": "^2.0.0",
|
||||
"@storybook/addons": "^6.5.9",
|
||||
"@storybook/react": "^6.5.9",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@babel/preset-react": "^7.22.5",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@storybook/addon-actions": "^7.0.23",
|
||||
"@storybook/addon-links": "^7.0.23",
|
||||
"@storybook/addon-styling": "^1.3.0",
|
||||
"@storybook/addons": "^7.0.23",
|
||||
"@storybook/react": "^7.0.23",
|
||||
"@storybook/react-webpack5": "^7.0.23",
|
||||
"@testing-library/dom": "^9.2.0",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^12.1.5",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@types/babel__preset-env": "^7",
|
||||
"@types/camelcase": "5.2.0",
|
||||
"@types/classnames": "^2.3.1",
|
||||
"@types/file-loader": "^5.0.0",
|
||||
|
@ -74,7 +78,7 @@
|
|||
"@types/rimraf": "3.0.0",
|
||||
"@types/sinon": "^10",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.3.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"babel-preset-react-app": "^10.0.1",
|
||||
"camelcase": "^6.3.0",
|
||||
"eslint": "^7.32.0",
|
||||
|
@ -91,10 +95,11 @@
|
|||
"prettier": "^2.3.1",
|
||||
"rimraf": "^5.0.0",
|
||||
"sass-loader": "^10.0.3",
|
||||
"storybook": "^7.0.23",
|
||||
"tailwindcss": "^3.3.1",
|
||||
"ts-jest": "^29.1.0",
|
||||
"typescript": "^4.9.3",
|
||||
"webpack": "^4.43.0"
|
||||
"webpack": "^5.84.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -2,39 +2,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { permitAdditionalJSImports } = require('fxa-react/configs/rescripts');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
devServer: (config) => {
|
||||
const oldWriteToDisk = config.writeToDisk
|
||||
? config.writeToDisk
|
||||
: () => false;
|
||||
const newConfig = {
|
||||
...config,
|
||||
writeToDisk: (path) =>
|
||||
/public\/locales\/\S+.ftl/.test(path) || oldWriteToDisk(path),
|
||||
};
|
||||
|
||||
return newConfig;
|
||||
},
|
||||
webpack: (config) => {
|
||||
let newConfig = { ...config };
|
||||
|
||||
if (!newConfig.output.path) {
|
||||
newConfig = {
|
||||
...newConfig,
|
||||
output: {
|
||||
...newConfig.output,
|
||||
path: path.resolve(fs.realpathSync(__dirname), 'build'),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return newConfig;
|
||||
},
|
||||
},
|
||||
permitAdditionalJSImports,
|
||||
];
|
||||
module.exports = [permitAdditionalJSImports];
|
||||
|
|
|
@ -3,6 +3,7 @@ import Page from '../Page';
|
|||
import Copiable from '../Copiable';
|
||||
import LinkExternal from 'fxa-react/components/LinkExternal';
|
||||
import Snippet from '../Snippet';
|
||||
import { withLocalization } from 'fxa-react/lib/storybooks';
|
||||
|
||||
/**
|
||||
* Note: we have a handful of concatenated classes here, which PurgeCSS will not observe
|
||||
|
@ -130,4 +131,4 @@ const Breakpoints = ({ config }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Breakpoints;
|
||||
export default (config) => withLocalization(() => Breakpoints(config));
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import Page from '../Page';
|
||||
import Copiable from '../Copiable';
|
||||
import Snippet from '../Snippet';
|
||||
import { withLocalization } from 'fxa-react/lib/storybooks';
|
||||
|
||||
const Swatch = ({
|
||||
color,
|
||||
|
@ -124,4 +125,4 @@ const Colors = ({ config }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Colors;
|
||||
export default (config) => withLocalization(() => Colors(config));
|
||||
|
|
|
@ -3,8 +3,9 @@ import Page from '../Page';
|
|||
import LinkExternal from 'fxa-react/components/LinkExternal';
|
||||
import Copiable from '../Copiable';
|
||||
import Snippet from '../Snippet';
|
||||
import { withLocalization } from 'fxa-react/lib/AppLocalizationProvider';
|
||||
|
||||
const Introduction = () => (
|
||||
export const Introduction = () => (
|
||||
<Page title="Introduction🎨">
|
||||
<div className="flex">
|
||||
<div className="max-w-3xl pr-6">
|
||||
|
@ -82,4 +83,4 @@ const Introduction = () => (
|
|||
</Page>
|
||||
);
|
||||
|
||||
export default Introduction;
|
||||
export default () => withLocalization(Introduction);
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import Page from '../Page';
|
||||
import Copiable from '../Copiable';
|
||||
import Snippet from '../Snippet';
|
||||
import { withLocalization } from 'fxa-react/lib/storybooks';
|
||||
|
||||
const nonIntMap = {
|
||||
px: {
|
||||
|
@ -209,4 +210,4 @@ const Spacing = ({ config }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Spacing;
|
||||
export default (config) => withLocalization(() => Spacing(config));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState } from 'react';
|
||||
import Page from '../Page';
|
||||
import Copiable from '../Copiable';
|
||||
import { withLocalization } from 'fxa-react/lib/AppLocalizationProvider';
|
||||
|
||||
/**
|
||||
* Note: we have a handful of concatenated classes here, which PurgeCSS will not observe
|
||||
|
@ -117,4 +118,4 @@ export const Typography = ({ config }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Typography;
|
||||
export default (config) => withLocalization(() => Typography(config));
|
||||
|
|
|
@ -5,17 +5,19 @@
|
|||
module.exports = {
|
||||
stories: ['./design-guide/main.stories.tsx', '../src/**/*.stories.tsx'],
|
||||
staticDirs: ['../public'],
|
||||
core: {
|
||||
builder: 'webpack5',
|
||||
},
|
||||
framework: {
|
||||
name: '@storybook/react-webpack5',
|
||||
options: {},
|
||||
},
|
||||
features: { storyStoreV7: false },
|
||||
addons: [
|
||||
'@storybook/addon-actions',
|
||||
'@storybook/addon-links',
|
||||
'storybook-addon-rtl',
|
||||
{
|
||||
name: '@storybook/addon-postcss',
|
||||
options: {
|
||||
postcssLoaderOptions: {
|
||||
implementation: require('postcss'),
|
||||
},
|
||||
},
|
||||
},
|
||||
'@storybook/addon-styling',
|
||||
'@storybook/preset-create-react-app',
|
||||
],
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"build-css": "tailwindcss -i ./src/styles/tailwind.css -o ./src/styles/tailwind.out.css --postcss",
|
||||
"build-storybook": "yarn merge-ftl && NODE_ENV=production STORYBOOK_BUILD=1 yarn build-css && yarn legal-clone && LOG_LEVEL=TRACE NODE_OPTIONS=--openssl-legacy-provider build-storybook && cp -r public/locales ./storybook-static/locales",
|
||||
"build-storybook": "yarn merge-ftl && NODE_ENV=production STORYBOOK_BUILD=1 yarn build-css && yarn legal-clone && LOG_LEVEL=TRACE NODE_OPTIONS=--openssl-legacy-provider storybook build && cp -r public/locales ./storybook-static/locales",
|
||||
"build": "tsc --build ../fxa-react && NODE_ENV=production yarn build-css && yarn legal-clone && yarn merge-ftl && SKIP_PREFLIGHT_CHECK=true INLINE_RUNTIME_CHUNK=false NODE_OPTIONS=--openssl-legacy-provider rescripts build",
|
||||
"compile": "tsc --noEmit",
|
||||
"clean": "git clean -fXd",
|
||||
|
@ -18,7 +18,7 @@
|
|||
"start": "yarn merge-ftl && yarn build-css && pm2 start pm2.config.js && ../../_scripts/check-url.sh localhost:3000/settings/static/js/bundle.js",
|
||||
"stop": "pm2 stop pm2.config.js",
|
||||
"delete": "pm2 delete pm2.config.js",
|
||||
"storybook": "yarn legal-clone && STORYBOOK_BUILD=1 yarn build-css && NODE_OPTIONS=--openssl-legacy-provider start-storybook -p 6008 --no-version-updates",
|
||||
"storybook": "yarn legal-clone && STORYBOOK_BUILD=1 yarn build-css && NODE_OPTIONS=--openssl-legacy-provider storybook dev -p 6008 --no-version-updates",
|
||||
"test": "yarn legal-clone && yarn merge-ftl-test && SKIP_PREFLIGHT_CHECK=true rescripts test --watchAll=false",
|
||||
"test-watch": "yarn legal-clone && yarn merge-ftl-test && SKIP_PREFLIGHT_CHECK=true rescripts test",
|
||||
"test-coverage": "yarn legal-clone && yarn test --coverage --watchAll=false",
|
||||
|
@ -71,7 +71,7 @@
|
|||
"@apollo/client": "^3.4.5",
|
||||
"@emotion/react": "^11.10.0",
|
||||
"@emotion/styled": "^11.10.4",
|
||||
"@fluent/react": "^0.13.1",
|
||||
"@fluent/react": "^0.14.1",
|
||||
"@material-ui/core": "v5.0.0-alpha.24",
|
||||
"@reach/router": "^1.3.4",
|
||||
"@types/material-ui": "^0.21.8",
|
||||
|
@ -91,7 +91,7 @@
|
|||
"react-easy-crop": "^4.7.4",
|
||||
"react-hook-form": "^6.15.8",
|
||||
"react-markdown": "^8.0.5",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-scripts": "^5.0.1",
|
||||
"react-webcam": "^7.0.0",
|
||||
"rehype-raw": "^6.1.1",
|
||||
"subscriptions-transport-ws": "^0.11.0",
|
||||
|
@ -99,15 +99,22 @@
|
|||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/core": "^7.22.5",
|
||||
"@babel/types": "^7.22.5",
|
||||
"@rescripts/cli": "0.0.16",
|
||||
"@sentry/browser": "^6.19.7",
|
||||
"@sentry/integrations": "^6.19.1",
|
||||
"@storybook/addon-actions": "^6.5.9",
|
||||
"@storybook/addon-links": "^6.5.9",
|
||||
"@storybook/addon-postcss": "^2.0.0",
|
||||
"@storybook/addons": "^6.5.9",
|
||||
"@storybook/react": "^6.5.9",
|
||||
"@storybook/addon-actions": "^7.0.23",
|
||||
"@storybook/addon-essentials": "^7.0.24",
|
||||
"@storybook/addon-interactions": "^7.0.24",
|
||||
"@storybook/addon-links": "^7.0.23",
|
||||
"@storybook/addon-styling": "^1.3.0",
|
||||
"@storybook/addons": "^7.0.23",
|
||||
"@storybook/blocks": "^7.0.24",
|
||||
"@storybook/preset-create-react-app": "^7.0.23",
|
||||
"@storybook/react": "^7.0.23",
|
||||
"@storybook/react-webpack5": "^7.0.23",
|
||||
"@storybook/testing-library": "^0.0.14-next.2",
|
||||
"@testing-library/dom": "^9.2.0",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^12.1.5",
|
||||
|
@ -118,6 +125,7 @@
|
|||
"@types/jest": "^26.0.23",
|
||||
"@types/lodash.groupby": "^4",
|
||||
"@types/node": "^18.14.2",
|
||||
"@types/prop-types": "^15",
|
||||
"@types/reach__router": "^1.3.11",
|
||||
"@types/react": "^17.0.14",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
|
@ -127,7 +135,8 @@
|
|||
"@types/uuid": "^8",
|
||||
"@types/webpack": "5.28.0",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"babel-loader": "^8.3.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"babel-plugin-named-exports-order": "^0.0.2",
|
||||
"css-loader": "^3.6.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-react-app": "^6.0.0",
|
||||
|
@ -144,11 +153,13 @@
|
|||
"postcss": "^8.4.14",
|
||||
"postcss-assets": "^6.0.0",
|
||||
"postcss-import": "^15.1.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"sinon": "^15.0.1",
|
||||
"storybook": "^7.0.23",
|
||||
"storybook-addon-rtl": "^0.5.0",
|
||||
"style-loader": "^1.3.0",
|
||||
"tailwindcss": "^3.3.1",
|
||||
"webpack": "^4.43.0"
|
||||
"webpack": "^5.84.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
import { render, act } from '@testing-library/react';
|
||||
import { act } from '@testing-library/react';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
import App from '.';
|
||||
import * as Metrics from '../../lib/metrics';
|
||||
import { useAccount, useInitialState } from '../../models';
|
||||
|
@ -70,7 +71,9 @@ describe('metrics', () => {
|
|||
};
|
||||
|
||||
await act(async () => {
|
||||
render(<App flowQueryParams={updatedFlowQueryParams} />);
|
||||
renderWithLocalizationProvider(
|
||||
<App flowQueryParams={updatedFlowQueryParams} />
|
||||
);
|
||||
});
|
||||
|
||||
expect(flowInit).toHaveBeenCalledWith(true, {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import React from 'react';
|
||||
import AppLayout from './index';
|
||||
import { Meta } from '@storybook/react';
|
||||
import { withLocalization } from '../../../.storybook/decorators';
|
||||
import { withLocalization } from 'fxa-react/lib/storybooks';
|
||||
|
||||
export default {
|
||||
title: 'Components/AppLayout',
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
import AppLayout from '.';
|
||||
|
||||
it('renders as expected with children', async () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<AppLayout>
|
||||
<p>Hello, world!</p>
|
||||
</AppLayout>
|
||||
|
|
|
@ -7,7 +7,7 @@ import Banner, { BannerType } from '.';
|
|||
import { Meta } from '@storybook/react';
|
||||
import AppLayout from '../AppLayout';
|
||||
import { Subject } from './mocks';
|
||||
import { withLocalization } from '../../../.storybook/decorators';
|
||||
import { withLocalization } from 'fxa-react/lib/storybooks';
|
||||
|
||||
export default {
|
||||
title: 'Components/Banner',
|
||||
|
|
|
@ -6,7 +6,7 @@ import React from 'react';
|
|||
import { Meta } from '@storybook/react';
|
||||
import AppLayout from '../AppLayout';
|
||||
import ButtonDownloadRecoveryKey, { fileContentVariation } from '.';
|
||||
import { withLocalization } from '../../../.storybook/decorators';
|
||||
import { withLocalization } from 'fxa-react/lib/storybooks';
|
||||
import { Account, AppContext } from '../../models';
|
||||
import { MOCK_ACCOUNT, mockAppContext } from '../../models/mocks';
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { fireEvent, screen } from '@testing-library/react';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
import { Account, AppContext } from '../../models';
|
||||
import { ButtonDownloadRecoveryKey } from '.';
|
||||
import { MOCK_ACCOUNT } from '../../models/mocks';
|
||||
|
@ -37,7 +38,7 @@ beforeAll(() => {
|
|||
|
||||
describe('ButtonDownloadRecoveryKey', () => {
|
||||
it('renders button as expected', () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={{ account }}>
|
||||
<ButtonDownloadRecoveryKey {...{ recoveryKeyValue, viewName }} />
|
||||
</AppContext.Provider>
|
||||
|
@ -46,7 +47,7 @@ describe('ButtonDownloadRecoveryKey', () => {
|
|||
});
|
||||
|
||||
it('sets the filename as expected with a reasonably-sized email', () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={{ account }}>
|
||||
<ButtonDownloadRecoveryKey {...{ recoveryKeyValue, viewName }} />
|
||||
</AppContext.Provider>
|
||||
|
@ -74,7 +75,7 @@ describe('ButtonDownloadRecoveryKey', () => {
|
|||
});
|
||||
|
||||
it('sets the filename with a truncated email as expected when the email is very long', () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={{ account: accountWithLongEmail }}>
|
||||
<ButtonDownloadRecoveryKey {...{ recoveryKeyValue, viewName }} />
|
||||
</AppContext.Provider>
|
||||
|
@ -98,7 +99,7 @@ describe('ButtonDownloadRecoveryKey', () => {
|
|||
// including validating that the expected key is included and matches the key in the DataBlock
|
||||
|
||||
it('emits a metrics event when the link is clicked', () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<AppContext.Provider value={{ account }}>
|
||||
<ButtonDownloadRecoveryKey {...{ recoveryKeyValue, viewName }} />
|
||||
</AppContext.Provider>
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
MOCK_SUBHEADING,
|
||||
} from './mocks';
|
||||
import { MozServices } from '../../lib/types';
|
||||
import { withLocalization } from '../../../.storybook/decorators';
|
||||
import { withLocalization } from 'fxa-react/lib/storybooks';
|
||||
|
||||
export default {
|
||||
title: 'Components/CardHeader',
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
import React from 'react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
import CardHeader from '.';
|
||||
import {
|
||||
MOCK_DEFAULT_HEADING_FTL_ID,
|
||||
|
@ -24,7 +25,7 @@ describe('CardHeader', () => {
|
|||
// });
|
||||
|
||||
it('renders as expected when no serviceName is provided', () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<CardHeader
|
||||
headingWithDefaultServiceFtlId={MOCK_DEFAULT_HEADING_FTL_ID}
|
||||
headingWithCustomServiceFtlId={MOCK_CUSTOM_HEADING_FTL_ID}
|
||||
|
@ -41,7 +42,7 @@ describe('CardHeader', () => {
|
|||
});
|
||||
|
||||
it('renders as expected when a serviceName is provided', () => {
|
||||
render(
|
||||
renderWithLocalizationProvider(
|
||||
<CardHeader
|
||||
headingWithDefaultServiceFtlId={MOCK_DEFAULT_HEADING_FTL_ID}
|
||||
headingWithCustomServiceFtlId={MOCK_CUSTOM_HEADING_FTL_ID}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче