Skip to content

Commit c59b1ad

Browse files
authored
Add console log and outputs (#39)
* feat(add console log preview): displays console log output to users Passes the console log output from the test to the frontend to be displayed for the user in a new output pane. * feat(multi-line outputs): adds multi line output to the hover tooltip When a single command results in multiple lines of output, we need to show all these lines to the user. * fix: add different underline for console log outputs Makes console log outputs underlined in yellow and errors underlined in red. * fix: fixes crash when history is reset * style: removing console logs * test: updating tests for new console log features * style: updating lint errors * build: update location of testing-library-visualizer import
1 parent 93397ec commit c59b1ad

17 files changed

+485
-269
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ The goal of this library is to make writing and debugging tests iteratively easi
99

1010
Install the package via:
1111

12-
```npm install react-testing-visualizer```
12+
```npm install testing-library-visualizer```
1313

1414
If you want to have your app's styling and assets available while debugging then you should build the application and put the following in a jest setup file. If you're using Create React App the following can go into `setupTests.js`. If you don't have a file that sets up the jest context, you can [specify one](https://jestjs.io/docs/configuration#setupfiles-array).
1515

1616
```javascript
1717
import {
1818
setup,
19-
} from "react-testing-visualizer";
19+
} from "testing-library-visualizer";
2020
import path from "path";
2121
import { expect } from "@jest/globals";
2222
import { screen, within, fireEvent } from "@testing-library/react";
@@ -32,15 +32,15 @@ registerCommands({ screen, within, fireEvent, userEvent, expect }); // This shou
3232
Once setup, debugging a test is simple. In the test file with the test you want to debug add:
3333

3434
```javascript
35-
import { debugTest } from "react-testing-visualizer";
35+
import { debugTest } from "testing-library-visualizer";
3636
```
3737

3838
Then replace `test` with `debugTest`. For example:
3939

4040
```javascript
4141
import { render } from "@testing-library/react";
4242
import App from "./App";
43-
import { debugTest } from "react-testing-visualizer";
43+
import { debugTest } from "testing-library-visualizer";
4444

4545
debugTest("Test App", async () => {
4646
render(<App />);
@@ -105,7 +105,7 @@ To do this you'll need to add the following to your jest test setup file.
105105
```javascript
106106
import {
107107
registerStyling,
108-
} from "react-testing-visualizer";
108+
} from "testing-library-visualizer";
109109

110110
registerStyling(/* <URL of styling> */);
111111
```
@@ -119,7 +119,7 @@ In many projects you'll define custom commands that you will want to run in the
119119
```javascript
120120
import {
121121
registerCommands,
122-
} from "react-testing-visualizer";
122+
} from "testing-library-visualizer";
123123

124124
registerCommands({
125125
test: () => {

package/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package/src/commandParser.js

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ function refresh() {
2525
let IDENTIFIER_MAP = {
2626
highlight,
2727
refresh,
28+
console,
2829
};
30+
2931
export const registerCommands = (commands) => {
3032
IDENTIFIER_MAP = { ...IDENTIFIER_MAP, ...commands };
3133
};
@@ -133,39 +135,71 @@ export async function runCommand(
133135
});
134136

135137
var lineNumber = 0;
138+
let consoleOutputs = [];
139+
140+
function parseLogs(lineNumber, consoleOutputs) {
141+
for (const consoleLog of consoleLogQueue) {
142+
if (!consoleLog.seen) {
143+
consoleLog.seen = true;
144+
145+
for (const arg of consoleLog.arguments) {
146+
if (consoleLog.method === "error") {
147+
consoleOutputs.push({
148+
type: "error",
149+
message: `Error printed to console.error. This error occurred asynchronously, and may have happened before this line was executed.\n\n${arg}`,
150+
lineNumber,
151+
});
152+
} else {
153+
consoleOutputs.push({
154+
message: String(arg),
155+
type: consoleLog.method,
156+
lineNumber,
157+
});
158+
}
159+
}
160+
}
161+
}
162+
}
136163

137164
try {
138165
if (parseTree.type !== "Program") {
139166
throw SyntaxError;
140167
}
141168

142-
for (const statement of parseTree.body) {
143-
await evaluator.traverseTree(statement);
144-
lineNumber += 1;
145-
}
146-
lineNumber -= 1;
147-
148169
function delay(time) {
149170
return new Promise((resolve) => setTimeout(resolve, time));
150171
}
151172

152-
await delay(10);
173+
for (const statement of parseTree.body) {
174+
await evaluator.traverseTree(statement);
153175

154-
for (const consoleLog of consoleLogQueue) {
155-
if (consoleLog.method === "error" && !consoleLog.seen) {
156-
consoleLog.seen = true;
157-
throw Error(
158-
`Error printed to console.error. This error occurred asynchronously, and may have happened before this line was executed.\n\n${consoleLog.arguments[0]}`
159-
);
160-
}
176+
parseLogs(lineNumber, consoleOutputs);
177+
lineNumber += 1;
161178
}
162179

163-
return { ok: true, error: null, lineNumber: null };
180+
lineNumber -= 1;
181+
await delay(1);
182+
183+
// Run this again after the delay in case there are more messages
184+
parseLogs(lineNumber, consoleOutputs);
185+
186+
return {
187+
ok: true,
188+
error: null,
189+
consoleOutputs,
190+
};
164191
} catch (error) {
165192
return {
166193
ok: false,
167-
error: { ...error, message: removeUnicodeColor(error.message) },
168-
lineNumber,
194+
error: { ...error },
195+
consoleOutputs: [
196+
...consoleOutputs,
197+
{
198+
type: "error",
199+
message: removeUnicodeColor(error.message),
200+
lineNumber,
201+
},
202+
],
169203
};
170204
}
171205
}

package/src/commandParser.test.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,25 +86,38 @@ function TestComponent() {
8686
return (
8787
<>
8888
{text}
89-
<button onClick={() => setTimeout(() => setText("Goodbye"), 5)}>
89+
<button onClick={() => setTimeout(() => setText("Goodbye"), 0)}>
9090
click me
9191
</button>
9292
</>
9393
);
9494
}
9595

9696
test("reports warnings", async () => {
97+
await debuggerSetup(async () => {
98+
render(<TestComponent />);
99+
const output = (
100+
await runCommand(
101+
"userEvent.click(screen.getByText('click me'))",
102+
consoleLogQueue
103+
)
104+
).consoleOutputs[0];
105+
expect(output.message).toEqual(
106+
expect.stringMatching(/not wrapped in act/g)
107+
);
108+
expect(output.type).toEqual("error");
109+
});
110+
});
111+
112+
test("reports console logs", async () => {
97113
await debuggerSetup(async () => {
98114
render(<TestComponent />);
99115

100-
expect(
101-
(
102-
await runCommand(
103-
"userEvent.click(screen.getByText('click me'))",
104-
consoleLogQueue
105-
)
106-
).error.message
107-
).toEqual(expect.stringMatching(/not wrapped in act/g));
116+
const output = (
117+
await runCommand("console.log('hello world')", consoleLogQueue)
118+
).consoleOutputs[0];
119+
expect(output.message).toEqual(expect.stringMatching(/hello world/g));
120+
expect(output.type).toEqual("log");
108121
});
109122
});
110123

package/src/testingUtil.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ export const debuggerSetup = async (fn) => {
6161
consoleLogQueue.push({ method: "log", arguments: arguments });
6262
return _log.apply(console, arguments);
6363
};
64+
console.log_without_reporting = function () {
65+
return _log.apply(console, arguments);
66+
};
6467

6568
console.warn = function () {
6669
consoleLogQueue.push({ method: "warn", arguments: arguments });
@@ -175,11 +178,7 @@ fastify.post("/command", async (request, reply) => {
175178
html: addStyleLinks(
176179
replaceFilePaths(document.documentElement.innerHTML, manifest)
177180
),
178-
error: output.error && {
179-
name: output.error.name,
180-
message: output.error.message,
181-
lineNumber: output.lineNumber,
182-
},
181+
consoleOutputs: output.consoleOutputs,
183182
};
184183
});
185184

@@ -200,7 +199,9 @@ export const start = async (setupFunction) => {
200199
await getCssFiles();
201200
await setupFunction();
202201
await fastify.listen(3001);
203-
console.log("Debug server is running, open at localhost:3001");
202+
console.log_without_reporting(
203+
"Debug server is running, open at localhost:3001"
204+
);
204205
while (isListening) {
205206
await sleep(50);
206207
}

test-app/package-lock.json

Lines changed: 31 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test-app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"react": "^17.0.2",
99
"react-dom": "^17.0.2",
1010
"react-scripts": "^5.0.0",
11-
"react-testing-visualizer": "file:../package",
11+
"testing-library-visualizer": "file:../package",
1212
"web-vitals": "^2.1.2"
1313
},
1414
"scripts": {

test-app/src/App.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { render, screen } from "@testing-library/react";
22
import App from "./App";
3-
import { debugTest } from "react-testing-visualizer";
3+
import { debugTest } from "testing-library-visualizer";
44

55
debugTest("renders learn react link", async () => {
66
render(<App />);

test-app/src/setupTests.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ import {
77
registerStyling,
88
setup,
99
registerCommands,
10-
} from "react-testing-visualizer";
10+
} from "testing-library-visualizer";
1111
import path from "path";
12+
import { screen, within, fireEvent } from "@testing-library/react";
13+
import userEvent from "@testing-library/user-event";
1214

1315
setup(path.join(__dirname, "..", "build"));
1416

1517
registerStyling("static/css/test.css");
16-
registerCommands({
17-
test: () => {
18-
console.log("test command");
19-
},
20-
});
18+
19+
registerCommands({ screen, within, fireEvent, userEvent, expect });

0 commit comments

Comments
 (0)