Skip to content

Add console log and outputs #39

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

Merged
merged 9 commits into from
Mar 23, 2022
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
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ The goal of this library is to make writing and debugging tests iteratively easi

Install the package via:

```npm install react-testing-visualizer```
```npm install testing-library-visualizer```

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).

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

```javascript
import { debugTest } from "react-testing-visualizer";
import { debugTest } from "testing-library-visualizer";
```

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

```javascript
import { render } from "@testing-library/react";
import App from "./App";
import { debugTest } from "react-testing-visualizer";
import { debugTest } from "testing-library-visualizer";

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

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

registerCommands({
test: () => {
Expand Down
4 changes: 2 additions & 2 deletions package/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 51 additions & 17 deletions package/src/commandParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ function refresh() {
let IDENTIFIER_MAP = {
highlight,
refresh,
console,
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add console as a default available command

};

export const registerCommands = (commands) => {
IDENTIFIER_MAP = { ...IDENTIFIER_MAP, ...commands };
};
Expand Down Expand Up @@ -133,39 +135,71 @@ export async function runCommand(
});

var lineNumber = 0;
let consoleOutputs = [];

function parseLogs(lineNumber, consoleOutputs) {
for (const consoleLog of consoleLogQueue) {
if (!consoleLog.seen) {
consoleLog.seen = true;

for (const arg of consoleLog.arguments) {
if (consoleLog.method === "error") {
consoleOutputs.push({
type: "error",
message: `Error printed to console.error. This error occurred asynchronously, and may have happened before this line was executed.\n\n${arg}`,
lineNumber,
});
} else {
consoleOutputs.push({
message: String(arg),
type: consoleLog.method,
lineNumber,
});
}
}
}
}
}

try {
if (parseTree.type !== "Program") {
throw SyntaxError;
}

for (const statement of parseTree.body) {
await evaluator.traverseTree(statement);
lineNumber += 1;
}
lineNumber -= 1;

function delay(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}

await delay(10);
for (const statement of parseTree.body) {
await evaluator.traverseTree(statement);

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

return { ok: true, error: null, lineNumber: null };
lineNumber -= 1;
await delay(1);

// Run this again after the delay in case there are more messages
parseLogs(lineNumber, consoleOutputs);

return {
ok: true,
error: null,
consoleOutputs,
};
} catch (error) {
return {
ok: false,
error: { ...error, message: removeUnicodeColor(error.message) },
lineNumber,
error: { ...error },
consoleOutputs: [
...consoleOutputs,
{
type: "error",
message: removeUnicodeColor(error.message),
lineNumber,
},
],
};
}
}
31 changes: 22 additions & 9 deletions package/src/commandParser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,25 +86,38 @@ function TestComponent() {
return (
<>
{text}
<button onClick={() => setTimeout(() => setText("Goodbye"), 5)}>
<button onClick={() => setTimeout(() => setText("Goodbye"), 0)}>
click me
</button>
</>
);
}

test("reports warnings", async () => {
await debuggerSetup(async () => {
render(<TestComponent />);
const output = (
await runCommand(
"userEvent.click(screen.getByText('click me'))",
consoleLogQueue
)
).consoleOutputs[0];
expect(output.message).toEqual(
expect.stringMatching(/not wrapped in act/g)
);
expect(output.type).toEqual("error");
});
});

test("reports console logs", async () => {
await debuggerSetup(async () => {
render(<TestComponent />);

expect(
(
await runCommand(
"userEvent.click(screen.getByText('click me'))",
consoleLogQueue
)
).error.message
).toEqual(expect.stringMatching(/not wrapped in act/g));
const output = (
await runCommand("console.log('hello world')", consoleLogQueue)
).consoleOutputs[0];
expect(output.message).toEqual(expect.stringMatching(/hello world/g));
expect(output.type).toEqual("log");
});
});

Expand Down
13 changes: 7 additions & 6 deletions package/src/testingUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export const debuggerSetup = async (fn) => {
consoleLogQueue.push({ method: "log", arguments: arguments });
return _log.apply(console, arguments);
};
console.log_without_reporting = function () {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retain an alias for the original console.log that we can use to output lines only to the console, and not to the user in the UI.

return _log.apply(console, arguments);
};

console.warn = function () {
consoleLogQueue.push({ method: "warn", arguments: arguments });
Expand Down Expand Up @@ -175,11 +178,7 @@ fastify.post("/command", async (request, reply) => {
html: addStyleLinks(
replaceFilePaths(document.documentElement.innerHTML, manifest)
),
error: output.error && {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer report errors separately, just send consoleOutputs with their type.

name: output.error.name,
message: output.error.message,
lineNumber: output.lineNumber,
},
consoleOutputs: output.consoleOutputs,
};
});

Expand All @@ -200,7 +199,9 @@ export const start = async (setupFunction) => {
await getCssFiles();
await setupFunction();
await fastify.listen(3001);
console.log("Debug server is running, open at localhost:3001");
console.log_without_reporting(
"Debug server is running, open at localhost:3001"
);
while (isListening) {
await sleep(50);
}
Expand Down
62 changes: 31 additions & 31 deletions test-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "^5.0.0",
"react-testing-visualizer": "file:../package",
"testing-library-visualizer": "file:../package",
"web-vitals": "^2.1.2"
},
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion test-app/src/App.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, screen } from "@testing-library/react";
import App from "./App";
import { debugTest } from "react-testing-visualizer";
import { debugTest } from "testing-library-visualizer";

debugTest("renders learn react link", async () => {
render(<App />);
Expand Down
11 changes: 5 additions & 6 deletions test-app/src/setupTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ import {
registerStyling,
setup,
registerCommands,
} from "react-testing-visualizer";
} from "testing-library-visualizer";
import path from "path";
import { screen, within, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

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

registerStyling("static/css/test.css");
registerCommands({
test: () => {
console.log("test command");
},
});

registerCommands({ screen, within, fireEvent, userEvent, expect });
Loading