Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

chore: added tests for fragment hooks #298

Merged
merged 3 commits into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ilc/server/tailor/fragment-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const parseLinkHeader = require('tailorx/lib/parse-link-header');

const { appIdToNameAndSlot } = require('../../common/utils');

function insertStart(stream, attributes, headers, index) {
function insertStart(stream, attributes, headers) {
const bundleVersionOverrides = _.pick(attributes, ['wrapperPropsOverride']);

if (headers.link) {
Expand Down
175 changes: 175 additions & 0 deletions ilc/server/tailor/fragment-hooks.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
const chai = require('chai');
const {getFragmentAttributes} = require('../../tests/helpers');
const {insertStart, insertEnd} = require('./fragment-hooks');
const {PassThrough} = require('stream');

describe('fragment-hooks', () => {
describe('insertEnd', () => {
it('should not write to stream', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes();
const headers = {};

insertEnd(mockStream, fragmentAttrs, headers);

chai.expect(mockStream.readableLength).to.be.equal(0);
});
});

describe('insertStart', () => {
it('should write a script tag with wrapper overrides', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes({
wrapperPropsOverride: {
param1: 'value1',
param2: 'value2',
}
});
const headers = {};

insertStart(mockStream, fragmentAttrs, headers);

const streamData = mockStream.read();

chai.expect(streamData).to.be.instanceOf(Buffer);
chai.expect(streamData.toString()).to.be.equal('<script type="spa-config-override">{"wrapperPropsOverride":{"param1":"value1","param2":"value2"}}</script>');
});


it('should write async fragment code warning comments for ref stylesheet ', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes({async: true});
const headers = {
link: '<https://domain.com/app.css>; rel="stylesheet"',
};

insertStart(mockStream, fragmentAttrs, headers);

const streamData = mockStream.read();

chai.expect(streamData).to.be.instanceOf(Buffer);
chai.expect(streamData.toString()).to.be.equal(
'<!-- Async fragments are not fully implemented yet: https://domain.com/app.css -->' +
'<script type="spa-config-override">{"cssBundle":"https://domain.com/app.css"}</script>'
);

});

it('should inject style link override function and script config override tag', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes({id: 'autogenerated_identifier'});
const headers = {
link: '<https://domain.com/app.css>; rel="stylesheet"',
};

insertStart(mockStream, fragmentAttrs, headers);

const streamData = mockStream.read();

chai.expect(streamData).to.be.instanceOf(Buffer);
chai.expect(streamData.toString()).to.be.equal(
'<script>(function(url, id){const link = document.head.querySelector(\'link[data-fragment-id="\' + id + \'"]\');if (link && link.href !== url) {link.href = url;}})("https://domain.com/app.css", "autogenerated_identifier");</script>' +
'<script type="spa-config-override">{"cssBundle":"https://domain.com/app.css"}</script>'
);
});

it('shouldn\'t inject style link override function if attribute.id hasn\'t been provided', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes({id: ''});
const headers = {
link: '<https://domain.com/app.css>; rel="stylesheet"',
};

insertStart(mockStream, fragmentAttrs, headers);

const streamData = mockStream.read();

chai.expect(streamData).to.be.instanceOf(Buffer);
chai.expect(streamData.toString()).to.be.equal(
'<script type="spa-config-override">{"cssBundle":"https://domain.com/app.css"}</script>'
);
});

it('should inject overrides with spaBundle', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes({id: 'autogenerated_identifier'});
const headers = {
link: '<https://domain.com/single_spa.js>; rel="fragment-script"; as="script"; crossorigin="anonymous"',
};

insertStart(mockStream, fragmentAttrs, headers);

const streamData = mockStream.read();
chai.expect(streamData).to.be.instanceOf(Buffer);
chai.expect(streamData.toString()).to.be.equal('<script type="spa-config-override">{"spaBundle":"https://domain.com/single_spa.js","appName":"autogenerated_identifier"}</script>');
});

it('should correct map appName for overrides', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes({
id: 'autogenerated_identifier',
wrapperConf: {
appId: 'wrapper__at__body',
name: '@portal/wrapper',
src: 'https://wrapper.com/fragment',
timeout: 2000
},
});

const headers = {
link: '<https://domain.com/single_spa.js>; rel="fragment-script"; as="script"; crossorigin="anonymous"',
};

insertStart(mockStream, fragmentAttrs, headers);

const streamData = mockStream.read();
chai.expect(streamData).to.be.instanceOf(Buffer);
chai.expect(streamData.toString()).to.be.equal('<script type="spa-config-override">{"spaBundle":"https://domain.com/single_spa.js","appName":"@portal/wrapper"}</script>');
});

it('should forward fragment dependency through overrides', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes({id: 'autogenerated_identifier'});
const headers = {
link: '<https://domain.com/single_spa.js>; rel="fragment-dependency"; name="dep_name"',
};

insertStart(mockStream, fragmentAttrs, headers);

const streamData = mockStream.read();

chai.expect(streamData).to.be.instanceOf(Buffer);
chai.expect(streamData.toString()).to.be.equal('<script type="spa-config-override">{"dependencies":{"dep_name":"https://domain.com/single_spa.js"}}</script>');
});

it('should forward a few fragment dependencies through overrides', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes({id: 'autogenerated_identifier'});
const headers = {
link: '<https://domain.com/single_spa.js>; rel="fragment-dependency"; name="dep_name", <https://domain2.com/single_spa2.js>; rel="fragment-dependency"; name="dep_name2"',
};

insertStart(mockStream, fragmentAttrs, headers);

const streamData = mockStream.read();

chai.expect(streamData).to.be.instanceOf(Buffer);
chai.expect(streamData.toString()).to.be.equal('<script type="spa-config-override">{"dependencies":{"dep_name":"https://domain.com/single_spa.js","dep_name2":"https://domain2.com/single_spa2.js"}}</script>');
});

it('shouldn\'t forward fragment dependency uri if its name hasn\'t been provided', () => {
const mockStream = new PassThrough();
const fragmentAttrs = getFragmentAttributes({id: 'autogenerated_identifier'});
const headers = {
link: '<https://domain.com/single_spa.js>; rel="fragment-script"; as="script"; crossorigin="anonymous", <https://domain.com/single_spa.js>; rel="fragment-dependency";',
};

insertStart(mockStream, fragmentAttrs, headers);

const streamData = mockStream.read();

chai.expect(streamData).to.be.instanceOf(Buffer);
chai.expect(streamData.toString()).to.be.equal('<script type="spa-config-override">{"spaBundle":"https://domain.com/single_spa.js","appName":"autogenerated_identifier"}</script>');
})
});
});
24 changes: 24 additions & 0 deletions ilc/tests/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,34 @@ function setupMockServersForApps() {
});
}

/**
* Returns mock attributes for tests
* @param overrideAttributes override default attributes
* @returns {{async: boolean, public: boolean, ignoreInvalidSsl: boolean, appProps: {}, wrapperConf: null, id: string, returnHeaders: boolean, url: string, timeout: number, primary: boolean, forwardQuerystring: boolean}}
*/
function getFragmentAttributes(overrideAttributes = {}) {
const defaultAttributes = {
id: 'microfrontend__at__slot',
appProps: {},
wrapperConf: null,
url: 'https://domain.com/',
async: false,
primary: false,
public: false,
timeout: 1000,
returnHeaders: false,
forwardQuerystring: false,
ignoreInvalidSsl: false,
}

return {...defaultAttributes, ...overrideAttributes};
}

module.exports = {
getRegistryMock,
getRouterProps,
getFragmentResponses,
getPluginManagerMock,
setupMockServersForApps,
getFragmentAttributes,
}