import * as utils from './ast-utils';
import * as ts from 'typescript';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { applyChangesToString, Tree } from '@nrwl/devkit';
describe('findDefaultExport', () => {
it('should find exported variable', () => {
const sourceCode = `
const main = () => {};
export default main;
`;
const source = ts.createSourceFile(
'test.ts',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = utils.findDefaultExport(source) as any;
expect(result).toBeDefined();
expect(result.name.text).toEqual('main');
});
it('should find exported function', () => {
const sourceCode = `
function main() {}
export default main;
`;
const source = ts.createSourceFile(
'test.ts',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = utils.findDefaultExport(source) as any;
expect(result).toBeDefined();
expect(result.name.text).toEqual('main');
});
it('should find default export function', () => {
const sourceCode = `
export default function main() {};
`;
const source = ts.createSourceFile(
'test.ts',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = utils.findDefaultExport(source) as any;
expect(result).toBeDefined();
expect(result.name.text).toEqual('main');
});
it('should find default class export', () => {
const sourceCode = `
export default class Main {};
`;
const source = ts.createSourceFile(
'test.ts',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = utils.findDefaultExport(source) as any;
expect(result).toBeDefined();
expect(result.name.text).toEqual('Main');
});
it('should find exported class', () => {
const sourceCode = `
class Main {};
export default Main;
`;
const source = ts.createSourceFile(
'test.ts',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = utils.findDefaultExport(source) as any;
expect(result).toBeDefined();
expect(result.name.text).toEqual('Main');
});
});
describe('addRoute', () => {
let tree: Tree;
let context: any;
beforeEach(() => {
context = {
warn: jest.fn(),
};
tree = createTreeWithEmptyWorkspace();
});
it('should add links and routes if they are not present', async () => {
const sourceCode = `
import React from 'react';
const App = () => (
<>
Hello
>
);
export default App;
`;
tree.write('/app.tsx', sourceCode);
const source = ts.createSourceFile(
'/app.tsx',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = applyChangesToString(
sourceCode,
utils.addInitialRoutes('/app.tsx', source)
);
expect(result).toMatch(/role="navigation"/);
expect(result).toMatch(/ {
const sourceCode = `
import React from 'react';
import { Home } from '@example/home';
const App = () => (
<>
Hello World!
>
);
export default App;
`;
tree.write('/app.tsx', sourceCode);
const source = ts.createSourceFile(
'/app.tsx',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = applyChangesToString(
sourceCode,
utils.addRoute('/app.tsx', source, {
routePath: '/about',
componentName: 'About',
moduleName: '@example/about',
})
);
expect(result).toMatch(/ {
let tree: Tree;
let context: any;
beforeEach(() => {
context = {
warn: jest.fn(),
};
tree = createTreeWithEmptyWorkspace();
});
it('should wrap around App component', () => {
const sourceCode = `
import React from 'react';
import ReactDOM from 'react-dom';
import { App } from '@example/my-app';
ReactDOM.render(, document.getElementById('root'));
`;
tree.write('/main.tsx', sourceCode);
const source = ts.createSourceFile(
'/main.tsx',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = applyChangesToString(
sourceCode,
utils.addBrowserRouter('/main.tsx', source)
);
expect(result).toContain('');
});
});
describe('findMainRenderStatement', () => {
let tree: Tree;
let context: any;
beforeEach(() => {
context = {
warn: jest.fn(),
};
tree = createTreeWithEmptyWorkspace();
});
it('should return render(...)', () => {
const sourceCode = `
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(, document.getElementById('root'));
`;
tree.write('/main.tsx', sourceCode);
const source = ts.createSourceFile(
'/main.tsx',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const node = utils.findMainRenderStatement(source);
expect(node).toBeTruthy();
});
it('should return render(...)', () => {
const sourceCode = `
import React from 'react';
import { render } from 'react-dom';
render(, document.getElementById('root'));
`;
tree.write('/main.tsx', sourceCode);
const source = ts.createSourceFile(
'/main.tsx',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const node = utils.findMainRenderStatement(source);
expect(node).toBeTruthy();
});
it('should return null when not found', () => {
const sourceCode = ``;
tree.write('/main.tsx', sourceCode);
const source = ts.createSourceFile(
'/main.tsx',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const node = utils.findMainRenderStatement(source);
expect(node).toBe(null);
});
});
describe('addReduxStoreToMain', () => {
let tree: Tree;
let context: any;
beforeEach(() => {
context = {
warn: jest.fn(),
};
tree = createTreeWithEmptyWorkspace();
});
it('should wrap around App component', () => {
const sourceCode = `
import React from 'react';
import ReactDOM from 'react-dom';
import { App } from '@example/my-app';
ReactDOM.render(, document.getElementById('root'));
`;
tree.write('/main.tsx', sourceCode);
const source = ts.createSourceFile(
'/main.tsx',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = applyChangesToString(
sourceCode,
utils.addReduxStoreToMain('/main.tsx', source)
);
expect(result).toContain('@reduxjs/toolkit');
expect(result).toContain('const store = configureStore');
expect(result).toContain('');
});
});
describe('updateReduxStore', () => {
let tree: Tree;
let context: any;
beforeEach(() => {
context = {
warn: jest.fn(),
};
tree = createTreeWithEmptyWorkspace();
});
it('should update configureStore call', () => {
const sourceCode = `
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
reducer: {}
});
`;
tree.write('/main.tsx', sourceCode);
const source = ts.createSourceFile(
'/main.tsx',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = applyChangesToString(
sourceCode,
utils.updateReduxStore('/main.tsx', source, {
keyName: 'SLICE_KEY',
reducerName: 'sliceReducer',
modulePath: '@test/slice',
})
);
expect(result).toContain(
"import { SLICE_KEY, sliceReducer } from '@test/slice'"
);
expect(result).toContain('[SLICE_KEY]: sliceReducer');
});
it('should update combineReducer call', () => {
const sourceCode = `
import { createStore, combineReducer } from 'redux';
const store = createStore(combineReducer({}));
`;
tree.write('/main.tsx', sourceCode);
const source = ts.createSourceFile(
'/main.tsx',
sourceCode,
ts.ScriptTarget.Latest,
true
);
const result = applyChangesToString(
sourceCode,
utils.updateReduxStore('/main.tsx', source, {
keyName: 'SLICE_KEY',
reducerName: 'sliceReducer',
modulePath: '@test/slice',
})
);
expect(result).toContain(
"import { SLICE_KEY, sliceReducer } from '@test/slice'"
);
expect(result).toContain('[SLICE_KEY]: sliceReducer');
});
});
describe('getComponentName', () => {
[
{
testName: 'exporting a function',
src: `export default function Test(props: TestProps) {
return (
Welcome to test component, {props.name}
);`,
expectedName: 'Test',
},
{
testName: 'defining a function and then default exporting it',
src: `
function Test(props: TestProps) {
return (
Welcome to test component, {props.name}
);
};
export default Test;
`,
expectedName: 'Test',
},
{
testName: 'defining an arrow function and then exporting it',
src: `
const Test = (props: TestProps) => {
return (
Welcome to test component, {props.name}
);
};
export default Test;
`,
expectedName: 'Test',
},
{
testName: 'defining an arrow function that directly returns JSX',
src: `
const Test = (props: TestProps) => Welcome to test component, {props.name}
;
export default Test
`,
expectedName: 'Test',
},
{
testName: 'exporting a react class component',
src: `
export default class Test extends React.Component {
render() {
return Welcome to test component, {this.props.name}
;
}
}
`,
expectedName: 'Test',
},
{
testName: 'defining a react class component & then default exporting it',
src: `
export default class Test extends React.Component {
render() {
return Welcome to test component, {this.props.name}
;
}
}
`,
expectedName: 'Test',
},
].forEach((testConfig) => {
it(`should find the component when ${testConfig.testName}`, () => {
const source = ts.createSourceFile(
'some-component.tsx',
testConfig.src,
ts.ScriptTarget.Latest,
true
);
const result = utils.getComponentName(source) as any;
expect(result).toBeDefined();
expect((result as any).name.text).toEqual(testConfig.expectedName);
});
});
it('should return null if there is no component', () => {
const source = ts.createSourceFile(
'some-component.tsx',
`console.log('hi there');`,
ts.ScriptTarget.Latest,
true
);
const result = utils.getComponentName(source) as any;
expect(result).toBeNull();
});
});