1 | const babel = require("@babel/core");
|
2 | const reactPlugin = require("../lib/index");
|
3 |
|
4 | function transform(
|
5 | code,
|
6 | { pluginsBefore = [], pluginsAfter = [], filename = "test.js" } = {}
|
7 | ) {
|
8 | return babel.transform(code, {
|
9 | filename,
|
10 | cwd: __dirname,
|
11 | plugins: [
|
12 | "@babel/plugin-syntax-jsx",
|
13 | ...pluginsBefore,
|
14 | reactPlugin,
|
15 | ...pluginsAfter,
|
16 | ],
|
17 | }).code;
|
18 | }
|
19 |
|
20 | const somePluginEnter = ({ types: t }) => ({
|
21 | visitor: {
|
22 | Program(path) {
|
23 | path.unshiftContainer(
|
24 | "body",
|
25 | t.importDeclaration(
|
26 | [t.importDefaultSpecifier(t.identifier("React"))],
|
27 | t.stringLiteral("react")
|
28 | )
|
29 | );
|
30 | },
|
31 | },
|
32 | });
|
33 |
|
34 | const somePluginExit = ({ types: t }) => ({
|
35 | visitor: {
|
36 | Program: {
|
37 | exit(path) {
|
38 | path.unshiftContainer(
|
39 | "body",
|
40 | t.importDeclaration(
|
41 | [t.importDefaultSpecifier(t.identifier("React"))],
|
42 | t.stringLiteral("react")
|
43 | )
|
44 | );
|
45 | },
|
46 | },
|
47 | },
|
48 | });
|
49 |
|
50 | const somePluginThatCrawl = () => ({
|
51 | visitor: {
|
52 | Program(path) {
|
53 | path.scope.crawl();
|
54 | },
|
55 | },
|
56 | });
|
57 |
|
58 | const somePluginCrazy = () => ({
|
59 | visitor: {
|
60 | Program(_, { file }) {
|
61 | file.get("ourPath").remove();
|
62 | },
|
63 | },
|
64 | });
|
65 |
|
66 | const genericInput =
|
67 | "export default class Component {render() {return <div />}}";
|
68 | const genericOutput =
|
69 | 'import React from "react";\nexport default class Component {\n render() {\n return <div />;\n }\n}';
|
70 |
|
71 | describe("babel-plugin-react", () => {
|
72 | it("should return transpiled code with required React", () => {
|
73 | const transformed = transform(genericInput);
|
74 |
|
75 | expect(transformed).toBe(genericOutput);
|
76 | });
|
77 |
|
78 | it("should return not transpiled code", () => {
|
79 | const transformed = transform(
|
80 | 'import x from "y";\nconsole.log("hello world")'
|
81 | );
|
82 |
|
83 | expect(transformed).toBe('import x from "y";\nconsole.log("hello world");');
|
84 | });
|
85 |
|
86 | it("should check that plugin does not import React twice", () => {
|
87 | const transformed = transform(
|
88 | "class Component{render(){return <div/>}} class Component2{render(){return <div />}}"
|
89 | );
|
90 |
|
91 | expect(transformed).toBe(
|
92 | 'import React from "react";\nclass Component {\n render() {\n return <div />;\n }\n}\n' +
|
93 | "class Component2 {\n render() {\n return <div />;\n }\n}"
|
94 | );
|
95 | });
|
96 |
|
97 | it("should does not replace users import on plugins import", () => {
|
98 | const transformed = transform(
|
99 | 'import React from"react/addons"\nclass Component{render(){return <div/>}}'
|
100 | );
|
101 |
|
102 | expect(transformed).toBe(
|
103 | 'import React from "react/addons";\nclass Component {\n render() {\n return <div />;\n }\n}'
|
104 | );
|
105 | });
|
106 |
|
107 | it("should get along with other plugins which add React import", () => {
|
108 | expect(transform(genericInput, { pluginsBefore: [somePluginEnter] })).toBe(
|
109 | genericOutput
|
110 | );
|
111 | expect(transform(genericInput, { pluginsBefore: [somePluginExit] })).toBe(
|
112 | genericOutput
|
113 | );
|
114 | expect(transform(genericInput, { pluginsAfter: [somePluginEnter] })).toBe(
|
115 | genericOutput
|
116 | );
|
117 | expect(transform(genericInput, { pluginsAfter: [somePluginExit] })).toBe(
|
118 | genericOutput
|
119 | );
|
120 | });
|
121 |
|
122 | it("should work with other plugins which use scope.crawl on files which already contains React import", () => {
|
123 | const transformed = transform('import * as React from "react";', {
|
124 | pluginsAfter: [somePluginThatCrawl],
|
125 | });
|
126 |
|
127 | expect(transformed).toBe('import * as React from "react";');
|
128 | });
|
129 |
|
130 | it("should not blow up if another plugin removes our import", () => {
|
131 | expect(transform(genericInput, { pluginsAfter: [somePluginCrazy] })).toBe(
|
132 | "export default class Component {\n render() {\n return <div />;\n }\n}"
|
133 | );
|
134 | expect(transform("const x = 1;", { pluginsAfter: [somePluginCrazy] })).toBe(
|
135 | "const x = 1;"
|
136 | );
|
137 | expect(
|
138 | transform("", {
|
139 | pluginsBefore: [somePluginEnter],
|
140 | pluginsAfter: [somePluginCrazy],
|
141 | })
|
142 | ).toBe('import React from "react";');
|
143 | });
|
144 |
|
145 | it("should support JSX fragments", () => {
|
146 | const transformed = transform("function Thing() {\n return <>Hi</>;\n}");
|
147 |
|
148 | expect(transformed).toBe(
|
149 | 'import React from "react";\nfunction Thing() {\n return <>Hi</>;\n}'
|
150 | );
|
151 | });
|
152 |
|
153 | it("should work with babel-plugin-inline-react-svg", () => {
|
154 | const transformed = transform('import svg from "./test.svg";', {
|
155 | filename: "test.svg",
|
156 | pluginsAfter: ["inline-react-svg"],
|
157 | });
|
158 |
|
159 | expect(transformed).toBe(
|
160 | 'import React from "react";\nvar svg = function svg(props) {\n return <svg {...props}><path fill="none" stroke="#000" strokeWidth="5" strokeOpacity=".5" d="M0 0h400v400H0z" /></svg>;\n};\nsvg.defaultProps = {\n xmlns: "http://www.w3.org/2000/svg"\n};'
|
161 | );
|
162 | });
|
163 | });
|