Skip to content

Conversation

dmohs
Copy link
Contributor

@dmohs dmohs commented Aug 8, 2022

No ticket - Test changes only. No code changes.

This creates a proxy to simulate API responses. The goal is to make UI tests faster and more reliable.

Most of the code is auto-generated from real API responses, so this change is smaller than it looks. You can ignore everything in the handlers directory, provided the code that generates those files looks sound.

TODO:
Handlers should not be a set of static files. Instead, each test should define the handlers to be used for that test.

@dmohs dmohs marked this pull request as ready for review August 18, 2022 17:02
yarn install
yarn codegen
REACT_APP_ENVIRONMENT=pr-site-$PR_SITE_NUM yarn run build --aot --no-watch --no-progress
REACT_APP_ENVIRONMENT=test yarn run build --aot --no-watch --no-progress
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we go with this approach, I will delete the unused PR site configuration files.

@@ -0,0 +1,19 @@
const matchReq = req => req.method === 'OPTIONS'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the only handler that is hand-edited. All of the OPTIONS method responses were basically identical, so I consolidated them into one file.

@@ -0,0 +1,28 @@
import * as nu from 'util'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Start of non-generated code.

const create = (logStream = process.stderr) => {
let lastStamp = -Infinity

const truncate = ms => Math.floor(ms / 60e3) * 60e3
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Codacy says this style of number can be inaccurate. However, (1) I disagree, (2) It wouldn't matter if they were, and (3) I think it is easier to see the value when not crowded with zeros.

Copy link
Collaborator

Choose a reason for hiding this comment

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

agree that codacy's rule doesn't make sense here

Copy link
Collaborator

@jmthibault79 jmthibault79 left a comment

Choose a reason for hiding this comment

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

What does .mjs signify?

Please update the README with how to run this locally, in replay and record modes

const create = (logStream = process.stderr) => {
let lastStamp = -Infinity

const truncate = ms => Math.floor(ms / 60e3) * 60e3
Copy link
Collaborator

Choose a reason for hiding this comment

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

agree that codacy's rule doesn't make sense here

req.startTimeMs = Date.now()
req.index = requestIndex++
res.index = req.index
req.log = (...formatArgs) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

what does this do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you mean the ...formatArgs part, which is just variadic arguments in JS (probably like ES2015+).

Copy link
Collaborator

@jmthibault79 jmthibault79 Aug 29, 2022

Choose a reason for hiding this comment

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

My concern is in in the details of this function: Why does the first arg 'f' get special treatment here?

If I'm interpreting this right, the log command has a mixture of substitution and positional formatting, which could be simplified to log('#%d %s', req.index, f, ...args), in which case I don't see the point of splitting out 'f' at all.


const quoteSingles = x => x.replace(/[']/g, '\\\'')
const quoteBackquotes = x => x.replace(/[`]/g, '\\`')
const formatObj = x => nu.inspect(x, {depth: Infinity, maxArrayLength: 10e3, breakLength: 100})
Copy link
Collaborator

Choose a reason for hiding this comment

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

what does this do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

inspect is a (awesome) Node utility that formats objects in a very readable way while still allowing them to be read via Node's interpreter. I've included a few options to ensure the output is less concise so it includes all of the data, but this is the workhorse that produces the fairly readable handlers directly from code.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this different from JSON.stringify() ?

const omit = ks => obj =>
Object.keys(obj).reduce((acc, k) => ks.includes(k) ? acc : ({...acc, [k]: obj[k]}), {})

const promiseEvent = eventName => x => new Promise(resolve => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

would "convert event to promise" be an accurate way to describe what this is doing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so. We're not transforming the event in any way. Instead, we're just waiting for it using the promise mechanism instead of a callback. "Promise event" here means, "promise me that you'll get an event in the future." I'm using promise in its verb form to return one in its noun form. Does that context make you think this name is a good choice?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not following. Not too surprising, since I don't really understand how events work. Also: I find curried functions to be an order of magnitude more difficult to read, so there's that too.

But this might be moot: I don't see that this is being used anywhere. Maybe it can be removed?

Copy link
Contributor Author

@dmohs dmohs left a comment

Choose a reason for hiding this comment

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

Since node supports "old style" require module semantics along with the now current import semantics, it uses the extension to determine which one you are using. At this time, import only works in "modules," which must have the .mjs extension.

Thanks for the reminder to update the README.

const omit = ks => obj =>
Object.keys(obj).reduce((acc, k) => ks.includes(k) ? acc : ({...acc, [k]: obj[k]}), {})

const promiseEvent = eventName => x => new Promise(resolve => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so. We're not transforming the event in any way. Instead, we're just waiting for it using the promise mechanism instead of a callback. "Promise event" here means, "promise me that you'll get an event in the future." I'm using promise in its verb form to return one in its noun form. Does that context make you think this name is a good choice?


const quoteSingles = x => x.replace(/[']/g, '\\\'')
const quoteBackquotes = x => x.replace(/[`]/g, '\\`')
const formatObj = x => nu.inspect(x, {depth: Infinity, maxArrayLength: 10e3, breakLength: 100})
Copy link
Contributor Author

Choose a reason for hiding this comment

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

inspect is a (awesome) Node utility that formats objects in a very readable way while still allowing them to be read via Node's interpreter. I've included a few options to ensure the output is less concise so it includes all of the data, but this is the workhorse that produces the fairly readable handlers directly from code.

req.startTimeMs = Date.now()
req.index = requestIndex++
res.index = req.index
req.log = (...formatArgs) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you mean the ...formatArgs part, which is just variadic arguments in JS (probably like ES2015+).

@dmohs dmohs merged commit 081eb79 into main Aug 26, 2022
@dmohs dmohs deleted the dmohs/api-proxy branch August 26, 2022 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants