Skip to content
This repository has been archived by the owner on May 3, 2024. It is now read-only.

Commit

Permalink
fix(provided-externals): logs warning for child modules (#32)
Browse files Browse the repository at this point in the history
* fix(provided-externals): logs warning for child modules

* feat(integration): add tests for required and provided externals

Co-authored-by: James Singleton <james.singleton1@aexp.com>
  • Loading branch information
Francois-Esquire and James Singleton authored Mar 26, 2020
1 parent 0b9b2b5 commit 24a9be4
Show file tree
Hide file tree
Showing 37 changed files with 23,094 additions and 40 deletions.
6 changes: 5 additions & 1 deletion __tests__/integration/helpers/moduleMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ const retrieveModuleIntegrityDigests = ({ moduleName, version }) => {
return integrityDigests;
};

const addModuleToModuleMap = async ({ moduleName, version, integrityDigests }) => {
const addModuleToModuleMap = async ({
moduleName,
version,
integrityDigests = retrieveModuleIntegrityDigests({ moduleName, version }),
}) => {
const gitSha = await retrieveGitSha();
const moduleMap = readModuleMap();
moduleMap.modules[moduleName] = {
Expand Down
161 changes: 161 additions & 0 deletions __tests__/integration/one-app.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,167 @@ describe('Tests that require Docker setup', () => {
});
});
});

describe('`providedExternals` and `requiredExternals` module configuration', () => {
afterAll(() => {
removeModuleFromModuleMap('late-frank');
});

describe('root module `providedExternals` usage', () => {
const providedExternalsModuleValidation = /Module frank-lloyd-root attempted to provide externals/;

const moduleName = 'frank-lloyd-root';
const version = '0.0.2';

let providedExternalsWarning;

beforeAll(async () => {
providedExternalsWarning = searchForNextLogMatch(providedExternalsModuleValidation);
await addModuleToModuleMap({
moduleName,
version,
});
// not ideal but need to wait for app to poll;
await waitFor(5000);
});

afterAll(() => {
writeModuleMap(originalModuleMap);
});

test('no warnings written to log if a root module is configured with `providedExternals`', async () => {
await expect(providedExternalsWarning).rejects.toEqual(
new Error('Failed to match: /Module frank-lloyd-root attempted to provide externals/ in logs')
);
});

test('loads root module correctly with styles from @emotion/core when the root module `providesExternals`',
async () => {
await browser.url(`${appAtTestUrls.browserUrl}/success`);
const headerBody = await browser.$('.helloMessage');
const headerText = await headerBody.getText();
const headerColor = await headerBody.getCSSProperty('background-color');
expect(headerText.includes('Hello! One App is successfully rendering its Modules!')).toBe(true);
expect(headerColor.value).toEqual('rgba(0,0,255,1)'); // color: blue;
});
});

describe('child module `providedExternals` invalid usage', () => {
const providedExternalsModuleValidation = /Module late-frank attempted to provide externals/;

const moduleName = 'late-frank';
const version = '0.0.1';

let providedExternalsWarning;

beforeAll(async () => {
providedExternalsWarning = searchForNextLogMatch(providedExternalsModuleValidation);
await addModuleToModuleMap({
moduleName,
version,
});
// not ideal but need to wait for app to poll;
await waitFor(5000);
});

afterAll(() => {
writeModuleMap(originalModuleMap);
});

test(
'writes a warning to log if a child module is configured with `providedExternals`',
async () => {
await expect(providedExternalsWarning).resolves
.toMatch(providedExternalsModuleValidation);
});

test('loads child module correctly with styles from @emotion/core regardless of mis-configuration',
async () => {
await browser.url(`${appAtTestUrls.browserUrl}/demo/late-frank`);
const headerBody = await browser.$('.lateFrank');
const headerText = await headerBody.getText();
const headerColor = await headerBody.getCSSProperty('color');
expect(headerText.includes('Sorry Im late!')).toBe(true);
expect(headerColor.value).toEqual('rgba(255,192,203,1)'); // color: pink;
});
});

describe('child module `requiredExternals` invalid usage', () => {
const requiredExternalsErrorMatch = /Failed to get external react-intl from root module/;

const moduleName = 'cultured-frankie';
const version = '0.0.1';

let requiredExternalsError;

beforeAll(async () => {
requiredExternalsError = searchForNextLogMatch(requiredExternalsErrorMatch);
await addModuleToModuleMap({
moduleName,
version,
});
// not ideal but need to wait for app to poll;

await waitFor(5000);
});

afterAll(() => {
writeModuleMap(originalModuleMap);
});

test('fails to get external `react-intl` for child module as an unsupplied `requiredExternal`', async () => {
await expect(requiredExternalsError).resolves.toMatch(requiredExternalsErrorMatch);
});

test('does not modify the original version "0.0.0" of the failing module', async () => {
const response = await fetch(`${appAtTestUrls.fetchUrl}/demo/${moduleName}`, {
...defaultFetchOptions,
});
const htmlData = await response.text();
expect(/<script.*cultured-frankie\/0\.0\.0.*>/.test(htmlData)).toBe(true);
});
});

describe('child module `requiredExternals` valid usage', () => {
const providedExternalsModuleValidation = /Module late-frank attempted to provide externals/;

const moduleName = 'late-frank';
const version = '0.0.2';

let providedExternalsWarning;

beforeAll(async () => {
providedExternalsWarning = searchForNextLogMatch(providedExternalsModuleValidation);
await addModuleToModuleMap({
moduleName,
version,
});
// not ideal but need to wait for app to poll;
await waitFor(5000);
});

afterAll(() => {
writeModuleMap(originalModuleMap);
});

test('does not write a warning to log if a child module is configured with `requiredExternals`', async () => {
await expect(providedExternalsWarning).rejects.toEqual(
new Error(
'Failed to match: /Module late-frank attempted to provide externals/ in logs'
)
);
});

test('loads child module correctly with styles from @emotion/core', async () => {
await browser.url(`${appAtTestUrls.browserUrl}/demo/late-frank`);
const headerBody = await browser.$('.lateFrank');
const headerText = await headerBody.getText();
const headerColor = await headerBody.getCSSProperty('color');
expect(headerText.includes('Sorry Im late!')).toBe(true);
expect(headerColor.value).toEqual('rgba(255,192,203,1)'); // color: pink;
});
});
});
});

describe('module requires SafeRequest Restricted Attributes not provided by tenant module', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ dep-b@~5.8.0 is required by my-awesome-module, but tenant root module provides 5
External 'dep-d' is required by my-awesome-module, but is not provided by tenant root module"
`;

exports[`onModuleLoad throws if a modules that isn't the tenant root module attempts to provide externals 1`] = `"Module my-awesome-module attempted to provide externals, but it is not the root module."`;

exports[`onModuleLoad throws if the tenant root module does not provide the expected external 1`] = `"External 'dep-b' is required by my-awesome-module, but is not provided by tenant root module"`;

exports[`onModuleLoad throws if the tenant root module provides an incompatible version of a required external 1`] = `"dep-a@^2.1.1 is required by my-awesome-module, but tenant root module provides 2.1.0"`;
Expand Down
6 changes: 4 additions & 2 deletions __tests__/server/utils/onModuleLoad.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const RootModule = () => <h1>Hello, world</h1>;
const csp = "default: 'none'";
describe('onModuleLoad', () => {
const consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(() => null);
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => null);

beforeEach(() => {
global.getTenantRootModule = () => RootModule;
Expand Down Expand Up @@ -184,7 +185,7 @@ describe('onModuleLoad', () => {
expect(() => onModuleLoad({ module: { [CONFIGURATION_KEY]: configuration, [META_DATA_KEY]: { version: '1.0.7' } }, moduleName: 'my-awesome-module' })).not.toThrow();
});

it('throws if a modules that isn\'t the tenant root module attempts to provide externals', () => {
it('warns if a module that isn\'t the tenant root module attempts to provide externals', () => {
const configuration = {
providedExternals: {
'dep-b': {
Expand All @@ -194,7 +195,8 @@ describe('onModuleLoad', () => {
},

};
expect(() => onModuleLoad({ module: { [CONFIGURATION_KEY]: configuration, [META_DATA_KEY]: { version: '1.0.8' } }, moduleName: 'my-awesome-module' })).toThrowErrorMatchingSnapshot();
onModuleLoad({ module: { [CONFIGURATION_KEY]: configuration, [META_DATA_KEY]: { version: '1.0.8' } }, moduleName: 'my-awesome-module' });
expect(consoleWarnSpy).toHaveBeenCalledTimes(1);
});

it('throws if the tenant root module does not provide the expected external', () => {
Expand Down
3 changes: 3 additions & 0 deletions prod-sample/sample-modules/cultured-frankie/0.0.1/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["amex"]
}
8 changes: 8 additions & 0 deletions prod-sample/sample-modules/cultured-frankie/0.0.1/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# node/npm
node_modules
*.log

# build
build
.webpack-stats.*
bundle.integrity.manifest.json
1 change: 1 addition & 0 deletions prod-sample/sample-modules/cultured-frankie/0.0.1/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
registry=https://registry.npmjs.org/
3 changes: 3 additions & 0 deletions prod-sample/sample-modules/cultured-frankie/0.0.1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# cultured-frankie

Module to demonstrate and test internationalization and requiredExternals
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"greeting": "Hello, my name is Frankie and I am in Canada!"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"greeting": "Hello, my name is Frankie and I am in the United States!"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"greeting": "Hola! Mi nombre es Frankie y estoy en Mexico!"
}
Loading

0 comments on commit 24a9be4

Please sign in to comment.