Skip to content
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
267 changes: 172 additions & 95 deletions packages/plugin-qiankun/src/common.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,107 +2,184 @@
* @author Kuitos
* @since 2019-10-22
*/
import 'jest';
import { testPathWithPrefix, insertRoute } from './common';

import { testPathWithPrefix } from './common';
describe('testPathPrefix', () => {
test('testPathPrefix', () => {
// browser history
expect(testPathWithPrefix('/js', '/')).toBeFalsy();

test('testPathPrefix', () => {
// browser history
expect(testPathWithPrefix('/js', '/')).toBeFalsy();
expect(testPathWithPrefix('/js', '/js')).toBeTruthy();
expect(testPathWithPrefix('/js', '/jss')).toBeFalsy();
expect(testPathWithPrefix('/js', '/js/')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/s')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/s/a')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/s?a=b')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js?a=b')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js?')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/?')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/?a=b')).toBeTruthy();

expect(testPathWithPrefix('/js', '/js')).toBeTruthy();
expect(testPathWithPrefix('/js', '/jss')).toBeFalsy();
expect(testPathWithPrefix('/js', '/js/')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/s')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/s/a')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/s?a=b')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js?a=b')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js?')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/?')).toBeTruthy();
expect(testPathWithPrefix('/js', '/js/?a=b')).toBeTruthy();
// hash history
expect(testPathWithPrefix('#/js', '#/js')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/jss')).toBeFalsy();
expect(testPathWithPrefix('#/js', '#/js/')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/s')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/s/a')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/s?a=b')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js?a=b')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js?')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/?')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/?a=b')).toBeTruthy();

// hash history
expect(testPathWithPrefix('#/js', '#/js')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/jss')).toBeFalsy();
expect(testPathWithPrefix('#/js', '#/js/')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/s')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/s/a')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/s?a=b')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js?a=b')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js?')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/?')).toBeTruthy();
expect(testPathWithPrefix('#/js', '#/js/?a=b')).toBeTruthy();
// browser history with slash ending
expect(testPathWithPrefix('/js/', '/js')).toBeFalsy();
expect(testPathWithPrefix('/js/', '/jss')).toBeFalsy();
expect(testPathWithPrefix('/js/', '/js/')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js/s')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js/s/a')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js/s?a=b')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js?a=b')).toBeFalsy();
expect(testPathWithPrefix('/js/', '/js?')).toBeFalsy();
expect(testPathWithPrefix('/js/', '/js/?')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js/?a=b')).toBeTruthy();

// browser history with slash ending
expect(testPathWithPrefix('/js/', '/js')).toBeFalsy();
expect(testPathWithPrefix('/js/', '/jss')).toBeFalsy();
expect(testPathWithPrefix('/js/', '/js/')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js/s')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js/s/a')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js/s?a=b')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js?a=b')).toBeFalsy();
expect(testPathWithPrefix('/js/', '/js?')).toBeFalsy();
expect(testPathWithPrefix('/js/', '/js/?')).toBeTruthy();
expect(testPathWithPrefix('/js/', '/js/?a=b')).toBeTruthy();
// hash history with slash ending
expect(testPathWithPrefix('#/js/', '#/js')).toBeFalsy();
expect(testPathWithPrefix('#/js/', '#/jss')).toBeFalsy();
expect(testPathWithPrefix('#/js/', '#/js/')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js/s')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js/s/a')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js/s?a=b')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js?a=b')).toBeFalsy();
expect(testPathWithPrefix('#/js/', '#/js?')).toBeFalsy();
expect(testPathWithPrefix('#/js/', '#/js/?')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js/?a=b')).toBeTruthy();

// hash history with slash ending
expect(testPathWithPrefix('#/js/', '#/js')).toBeFalsy();
expect(testPathWithPrefix('#/js/', '#/jss')).toBeFalsy();
expect(testPathWithPrefix('#/js/', '#/js/')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js/s')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js/s/a')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js/s?a=b')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js?a=b')).toBeFalsy();
expect(testPathWithPrefix('#/js/', '#/js?')).toBeFalsy();
expect(testPathWithPrefix('#/js/', '#/js/?')).toBeTruthy();
expect(testPathWithPrefix('#/js/', '#/js/?a=b')).toBeTruthy();
// browser history with dynamic route
expect(testPathWithPrefix('/:abc', '/js')).toBeTruthy();
expect(testPathWithPrefix('/:abc', '/123')).toBeTruthy();
expect(testPathWithPrefix('/:abc/', '/js/')).toBeTruthy();
expect(testPathWithPrefix('/:abc/js', '/js/js')).toBeTruthy();
expect(testPathWithPrefix('/:abc/js', '/js/123')).toBeFalsy();
expect(testPathWithPrefix('/js/:abc', '/js/123')).toBeTruthy();
expect(testPathWithPrefix('/js/:abc/', '/js/123')).toBeFalsy();
expect(testPathWithPrefix('/js/:abc/jsx', '/js/123/jsx')).toBeTruthy();
expect(
testPathWithPrefix('/js/:abc/jsx', '/js/123/jsx/hello'),
).toBeTruthy();
expect(testPathWithPrefix('/js/:abc/jsx', '/js/123')).toBeFalsy();
expect(testPathWithPrefix('/js/:abc/jsx', '/js/123/css')).toBeFalsy();
expect(
testPathWithPrefix('/js/:abc/jsx/:cde', '/js/123/jsx/kkk'),
).toBeTruthy();
expect(testPathWithPrefix('/js/:abc/jsx/:cde', '/js/123/jsk')).toBeFalsy();
expect(
testPathWithPrefix('/js/:abc/jsx/:cde', '/js/123/jsx/kkk/hello'),
).toBeTruthy();
expect(testPathWithPrefix('/js/:abc?', '/js')).toBeTruthy();
expect(testPathWithPrefix('/js/*', '/js/245')).toBeTruthy();

// browser history with dynamic route
expect(testPathWithPrefix('/:abc', '/js')).toBeTruthy();
expect(testPathWithPrefix('/:abc', '/123')).toBeTruthy();
expect(testPathWithPrefix('/:abc/', '/js/')).toBeTruthy();
expect(testPathWithPrefix('/:abc/js', '/js/js')).toBeTruthy();
expect(testPathWithPrefix('/:abc/js', '/js/123')).toBeFalsy();
expect(testPathWithPrefix('/js/:abc', '/js/123')).toBeTruthy();
expect(testPathWithPrefix('/js/:abc/', '/js/123')).toBeFalsy();
expect(testPathWithPrefix('/js/:abc/jsx', '/js/123/jsx')).toBeTruthy();
expect(testPathWithPrefix('/js/:abc/jsx', '/js/123/jsx/hello')).toBeTruthy();
expect(testPathWithPrefix('/js/:abc/jsx', '/js/123')).toBeFalsy();
expect(testPathWithPrefix('/js/:abc/jsx', '/js/123/css')).toBeFalsy();
expect(
testPathWithPrefix('/js/:abc/jsx/:cde', '/js/123/jsx/kkk'),
).toBeTruthy();
expect(testPathWithPrefix('/js/:abc/jsx/:cde', '/js/123/jsk')).toBeFalsy();
expect(
testPathWithPrefix('/js/:abc/jsx/:cde', '/js/123/jsx/kkk/hello'),
).toBeTruthy();
expect(testPathWithPrefix('/js/:abc?', '/js')).toBeTruthy();
expect(testPathWithPrefix('/js/*', '/js/245')).toBeTruthy();
// hash history with dynamic route
expect(testPathWithPrefix('#/:abc', '#/js')).toBeTruthy();
expect(testPathWithPrefix('#/:abc', '#/123')).toBeTruthy();
expect(testPathWithPrefix('#/:abc/', '#/js/')).toBeTruthy();
expect(testPathWithPrefix('#/:abc/js', '#/js/js')).toBeTruthy();
expect(testPathWithPrefix('#/:abc/js', '#/js/123')).toBeFalsy();
expect(testPathWithPrefix('#/js/:abc', '#/js/123')).toBeTruthy();
expect(testPathWithPrefix('#/js/:abc/', '#/js/123')).toBeFalsy();
expect(testPathWithPrefix('#/js/:abc/', '#/js/123/jsx')).toBeTruthy();
expect(testPathWithPrefix('#/js/:abc/jsx', '#/js/123/jsx')).toBeTruthy();
expect(
testPathWithPrefix('#/js/:abc/jsx', '#/js/123/jsx/hello'),
).toBeTruthy();
expect(
testPathWithPrefix('#/js/:abc/jsx', '#/js/123/jsx/hello?test=1'),
).toBeTruthy();
expect(testPathWithPrefix('#/js/:abc/jsx', '#/js/123')).toBeFalsy();
expect(testPathWithPrefix('#/js/:abc/jsx', '#/js/123/css')).toBeFalsy();
expect(
testPathWithPrefix('#/js/:abc/jsx/:cde', '#/js/123/jsx/kkk'),
).toBeTruthy();
expect(
testPathWithPrefix('#/js/:abc/jsx/:cde', '#/js/123/jsx/kkk/hello'),
).toBeTruthy();
expect(
testPathWithPrefix('#/js/:abc/jsx/:cde', '#/js/123/jsk'),
).toBeFalsy();
expect(testPathWithPrefix('#/js/:abc?', '#/js')).toBeTruthy();
expect(testPathWithPrefix('#/js/*', '#/js/245')).toBeTruthy();
});
});

describe('test insert route', () => {
test('insert', () => {
const mockRoutes = [{ path: '/a' }];
insertRoute(mockRoutes, { path: '/a/b', insert: '/a' });
expect(mockRoutes).toEqual([
{ path: '/a', exact: false, routes: [{ insert: '/a', path: '/a/b' }] },
]);
});
test('insert with children routes', () => {
const mockRoutes = [{ path: '/a' }];
insertRoute(mockRoutes, {
path: '/a/b',
insert: '/a',
routes: [{ path: '/a/b/c' }],
});
expect(mockRoutes).toEqual([
{
path: '/a',
exact: false,
routes: [{ insert: '/a', path: '/a/b', routes: [{ path: '/a/b/c' }] }],
},
]);
});
test('insert into children routes', () => {
const mockRoutes = [{ path: '/a', routes: [{ path: '/a/b' }] }];
insertRoute(mockRoutes, { path: '/a/b/c', insert: '/a/b' });
expect(mockRoutes).toEqual([
{
path: '/a',
routes: [
{
path: '/a/b',
exact: false,
routes: [{ path: '/a/b/c', insert: '/a/b' }],
},
],
},
]);
});

test('insert node does not exist', () => {
const mockRoutes = [{ path: '/a' }];
const mockInsert = { path: '/a/b', insert: '/b' };
const errorFn = jest.fn();
try {
insertRoute(mockRoutes, mockInsert);
} catch (e) {
errorFn();
expect(e.message).toEqual(
`[plugin-qiankun]: path "${mockInsert.insert}" not found`,
);
}
expect(errorFn).toBeCalled();
});

// hash history with dynamic route
expect(testPathWithPrefix('#/:abc', '#/js')).toBeTruthy();
expect(testPathWithPrefix('#/:abc', '#/123')).toBeTruthy();
expect(testPathWithPrefix('#/:abc/', '#/js/')).toBeTruthy();
expect(testPathWithPrefix('#/:abc/js', '#/js/js')).toBeTruthy();
expect(testPathWithPrefix('#/:abc/js', '#/js/123')).toBeFalsy();
expect(testPathWithPrefix('#/js/:abc', '#/js/123')).toBeTruthy();
expect(testPathWithPrefix('#/js/:abc/', '#/js/123')).toBeFalsy();
expect(testPathWithPrefix('#/js/:abc/', '#/js/123/jsx')).toBeTruthy();
expect(testPathWithPrefix('#/js/:abc/jsx', '#/js/123/jsx')).toBeTruthy();
expect(
testPathWithPrefix('#/js/:abc/jsx', '#/js/123/jsx/hello'),
).toBeTruthy();
expect(
testPathWithPrefix('#/js/:abc/jsx', '#/js/123/jsx/hello?test=1'),
).toBeTruthy();
expect(testPathWithPrefix('#/js/:abc/jsx', '#/js/123')).toBeFalsy();
expect(testPathWithPrefix('#/js/:abc/jsx', '#/js/123/css')).toBeFalsy();
expect(
testPathWithPrefix('#/js/:abc/jsx/:cde', '#/js/123/jsx/kkk'),
).toBeTruthy();
expect(
testPathWithPrefix('#/js/:abc/jsx/:cde', '#/js/123/jsx/kkk/hello'),
).toBeTruthy();
expect(testPathWithPrefix('#/js/:abc/jsx/:cde', '#/js/123/jsk')).toBeFalsy();
expect(testPathWithPrefix('#/js/:abc?', '#/js')).toBeTruthy();
expect(testPathWithPrefix('#/js/*', '#/js/245')).toBeTruthy();
test('insert path does not follow hierarchy', () => {
const mockRoutes = [{ path: '/a' }];
const mockInsert = { path: '/b', insert: '/a' };
const errorFn = jest.fn();
try {
insertRoute(mockRoutes, mockInsert);
} catch (e) {
errorFn();
expect(e.message).toEqual(
`[plugin-qiankun]: path "${mockInsert.path}" need to starts with "${mockRoutes[0].path}"`,
);
}
expect(errorFn).toBeCalled();
});
});
41 changes: 41 additions & 0 deletions packages/plugin-qiankun/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { ReactComponentElement } from 'react';
import type { IRouteProps } from 'umi';

export const defaultMountContainerId = 'root-subapp';

Expand Down Expand Up @@ -88,3 +89,43 @@ export function patchMicroAppRoute(
route.component = getMicroAppRouteComponent(opts);
}
}

const recursiveSearch = (
routes: IRouteProps[],
path: string,
): IRouteProps | null => {
for (let i = 0; i < routes.length; i++) {
if (routes[i].path === path) {
return routes[i];
}
if (routes[i].routes && routes[i].routes?.length) {
const found = recursiveSearch(routes[i].routes || [], path);
if (found) {
return found;
}
}
}
return null;
};

export function insertRoute(routes: IRouteProps[], microAppRoute: IRouteProps) {
const found = recursiveSearch(routes, microAppRoute.insert);
if (found) {
if (
!microAppRoute.path ||
!found.path ||
!microAppRoute.path.startsWith(found.path)
) {
throw new Error(
`[plugin-qiankun]: path "${microAppRoute.path}" need to starts with "${found.path}"`,
);
}
found.exact = false;
found.routes = found.routes || [];
found.routes.push(microAppRoute);
} else {
throw new Error(
`[plugin-qiankun]: path "${microAppRoute.insert}" not found`,
);
}
}
Loading