Skip to content
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

[RW-5959][risk=no] Upgrade jest to latest version #4733

Merged
merged 18 commits into from Apr 1, 2021
Merged

Conversation

aweng98
Copy link
Contributor

@aweng98 aweng98 commented Mar 23, 2021

Retry reverted PR commit 4287.

@@ -7,7 +7,7 @@ import {Runtime} from 'generated/fetch';
import {RuntimeStatus} from 'generated/fetch';
import {RuntimeApi} from 'generated/fetch/api';
import SpyInstance = jest.SpyInstance;
import expect = jest.Expect;
import { expect } from '@jest/globals';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fix ts error from jest.assertions usage in this file.
Screen Shot 2021-03-23 at 7 26 43 PM

ui/package.json Outdated
@@ -25,7 +25,7 @@
"./test-shim.js",
"./test-setup.js"
],
"setupTestFrameworkScriptFile": "./test-setup-script.js",
"setupFilesAfterEnv": ["./test-setup-script.js"],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Jest deprecated setupTestFrameworkScriptFile in favor of new setupFilesAfterEnv (#7119)

@aweng98 aweng98 changed the title [RW-5959][risk=no] Upgrade jest and related packages to latest versions [RW-5959][risk=no] Upgrade jest to latest version Mar 24, 2021
@@ -248,7 +248,7 @@ export const CohortSearch = withCurrentCohortSearchContext()(class extends React
clearTimeout(this.growlTimer);
}
// This is to set style display: 'none' on the growl so it doesn't block the nav icons in the sidebar
this.growlTimer = setTimeout(() => this.setState({growlVisible: false}), 2500);
this.growlTimer = global.setTimeout(() => this.setState({growlVisible: false}), 2500);
Copy link
Contributor Author

@aweng98 aweng98 Mar 25, 2021

Choose a reason for hiding this comment

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

Resolving typescript issue

@@ -7,12 +7,10 @@
// No outDir needs to be specified here, as test runs will not produce output files anyway.
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

target: "es6" inherited from ../tsconfig.json.

"types": [
"jest",
"node"
],
"jsx": "react"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

inherited from ../tsconfig.json

Comment on lines -14 to -16
"typeRoots": [
"node_modules/@types"
],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

defining typeRoots is unnecessary. It is part of the default value.
https://www.typescriptlang.org/tsconfig#typeRoots

Comment on lines +436 to +439
if (valueKey && !Array.isArray(valueKey)) {
valueKey = [valueKey];
}
if (valueKey && valueKey.length > 1) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The profile-page.spec.tsx was failing consistently after versions upgrade. @ch helped me and figured out it was caused by a bug here.

Copy link
Contributor

@calbach calbach left a comment

Choose a reason for hiding this comment

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

Looks good - but would like @petesantos' review on the line I mentioned before merging in case I'm missing something.

@@ -433,7 +433,10 @@ export const ProfilePage = fp.flow(

const makeProfileInput = ({title, valueKey, isLong = false, ...props}) => {
let errorText = profile && errors && errors[valueKey];
if (valueKey && Array.isArray(valueKey) && valueKey.length > 1) {
if (valueKey && !Array.isArray(valueKey)) {
valueKey = [valueKey];
Copy link
Contributor

Choose a reason for hiding this comment

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

@petesantos can you review this specific change? Based on my reading of the previous code, L444 when the valueKey is 'givenName', the array expansion should equate to:

this.setState(fp.set(['currentProfile', 'g', 'i', 'v', 'e', 'n', 'N', 'a', 'm', 'e'], v)) 

With Alex's change, the test started failing from this somehow. Do you have ideas on what's going on here? I'm still puzzled as to how the current code is functional.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is interesting, it looks like JS and TS handle spread differently. When the TS compiles down to javascript it must do something to prevent strings from getting split apart on a spread. The new code looks more correct and in-line with what I would expect. I will put together a code example demonstrating this issue. What was the specific error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

UI unit profile-page test failure:

FAIL src/app/pages/profile/profile-page.spec.tsx
  ● ProfilePageComponent › should invalidate inputs correctly

    expect(received).toBeTruthy()

    Received: false

      88 |     const wrapper = component();
      89 |     wrapper.find(TextInput).first().simulate('change', {target: {value: ''}});
    > 90 |     expect(wrapper.find(TextInput).first().prop('invalid')).toBeTruthy();
         |                                                             ^
      91 |   });
      92 | 
      93 |   it('should display/update address', async() => {

      at Object.<anonymous> (src/app/pages/profile/profile-page.spec.tsx:90:61)

Copy link
Contributor

@calbach calbach Mar 31, 2021

Choose a reason for hiding this comment

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

Cool, thanks - it should be possible to set up a more isolated reproducer here (the above failure is highly detached from the cause, and required some trial and error to trace down), I can try and help set this up as well if you'd like.

For the purposes of this PR I think it should be fine to merge now. Pete's comment of "The new code looks more correct and in-line with what I would expect" answers what I was looking for, which is to make sure I wasn't missing something obvious and that the change makes sense.

Copy link
Contributor

@petesantos petesantos Apr 1, 2021

Choose a reason for hiding this comment

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

So this is the issue:

This Typescript code (in version 3.2.z)

const checkValueKey = (valueKey) => {
  console.log(['test', ...valueKey])
}

checkValueKey('test')

compiles to this in javascript:

var checkValueKey = function (valueKey) {
    console.log(['test'].concat(valueKey));
};
checkValueKey('test');

When using concat as a spread operator you will see the behavior we are seeing in the code. The string item in the concat will not be split apart.

However, the same code when compiled in TS 4.2.3 yields:

var __spreadArray = (this && this.__spreadArray) || function (to, from) {
    for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
        to[j] = from[i];
    return to;
};
var checkValueKey = function (valueKey) {
    console.log(__spreadArray(['test'], valueKey));
};
checkValueKey('test');

Where the __spreadArray function more closely follows what JS does with the spread operator, splitting apart the string.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice find! Thanks. That seems like the likely culprit.

Something that's still not obvious to me though is why the typescript version changed with this PR, that seems like an unexpected side effect. My best guess is that changing ts-jest changed the Typescript version behind the scenes for tests, but if so this interaction is not obvious from yarn.lock or from the ts-jest docs.

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like "ts-jest": "^26.5.4" uses TypeScript 4.x. This is probably why this error cropped up in the test.

This is a caveat we should be aware of - the jest tests will be using a different version of typescript from our code.

Copy link
Contributor

@petesantos petesantos Apr 1, 2021

Choose a reason for hiding this comment

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

One more update - I was wondering what our ES target version was, and whether a change to that would prevent substituting the spread operator at all, I don't think there is any browser we are targeting that doesn't support this.
Looking at the tsconfig.json L13 we are changing our ES target to es6 in this change.
Prior to this change, the code in question would compile to this (note the concat) :

return _this.setState(lodash_fp__WEBPACK_IMPORTED_MODULE_1__["set"](['currentProfile'].concat(valueKey), v));

and it now compiles to:

onChange: v => this.setState(lodash_fp__WEBPACK_IMPORTED_MODULE_1__["set"](['currentProfile', ...valueKey], v)),

I am curious as to whether the error popped up as a result of the target change, or the jest upgrade. In other words - is jest using a different typescript version from our build?

Copy link
Contributor

Choose a reason for hiding this comment

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

Alright... Final update... just for a full understanding of what is happening.
It looks like ts-jest is using our version of TS, the real issue is with the target change in the config and how it effects the resulting Javascript that comes out.

This is what I tested to confirm the behavior of the tests:

ts-jest version  | target | result
----------------------------------------------
25.3.0           | es5    |  pass (because it uses concat )
25.3.0           | es6    |  fail (uses spread operator)
26.5.4           | es5    |  pass (uses concat) --> If this were using 4.x of TS it would fail by using `__spreadArray`
26.5.4           | es6    |  fail (uses spread operator)

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 100% confident but it looks to me that there was one usage of valueKey that this missed:
valueKey: 'verifiedInstitutionalAffiliation.institutionDisplayName' -> #4822

@@ -7,7 +7,7 @@ import {Runtime} from 'generated/fetch';
import {RuntimeStatus} from 'generated/fetch';
import {RuntimeApi} from 'generated/fetch/api';
import SpyInstance = jest.SpyInstance;
import expect = jest.Expect;
import { expect } from '@jest/globals';
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: general convention in the codebase (and this file) is {expect} instead of { expect }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍🏻

@@ -433,7 +433,10 @@ export const ProfilePage = fp.flow(

const makeProfileInput = ({title, valueKey, isLong = false, ...props}) => {
let errorText = profile && errors && errors[valueKey];
if (valueKey && Array.isArray(valueKey) && valueKey.length > 1) {
if (valueKey && !Array.isArray(valueKey)) {
valueKey = [valueKey];
Copy link
Contributor

Choose a reason for hiding this comment

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

Alright... Final update... just for a full understanding of what is happening.
It looks like ts-jest is using our version of TS, the real issue is with the target change in the config and how it effects the resulting Javascript that comes out.

This is what I tested to confirm the behavior of the tests:

ts-jest version  | target | result
----------------------------------------------
25.3.0           | es5    |  pass (because it uses concat )
25.3.0           | es6    |  fail (uses spread operator)
26.5.4           | es5    |  pass (uses concat) --> If this were using 4.x of TS it would fail by using `__spreadArray`
26.5.4           | es6    |  fail (uses spread operator)

ui/package.json Outdated
@@ -117,7 +121,7 @@
"serialize-javascript": "^3.1.0",
"stackdriver-errors-js": "^0.4.0",
"stacktrace-js": "^2.0.0",
"ts-jest": "^25.3.0",
"ts-jest": "^26.5.4",
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be moved to devDependencies?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Done.

Copy link
Contributor Author

@aweng98 aweng98 left a comment

Choose a reason for hiding this comment

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

Additional changes to address PR feedback and tests failures:

  • Updated notebook download menu functions because Puppeteer notebook-download test. menu clicking is not working 100% of time from PR changes.
  • Reverted target back to es5.
  • Edited polyfills.ts to resolve a new error.

* Resolving ERROR: ReferenceError: global is not defined.
*
*/
(window as any).global = window;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Puppeteer notebook tests were failing. Failures were caused by ReferenceError: global is not defined.
Screen Shot 2021-04-01 at 11 35 31 AM

@aweng98
Copy link
Contributor Author

aweng98 commented Apr 1, 2021

I made more changes and fixed broken tests. CircleCI testing passed 2 of 2. Could you do a final review? Just to verify new changes made today are okay.

Copy link
Contributor

@petesantos petesantos left a comment

Choose a reason for hiding this comment

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

Adding the global variable and changing the code to use the global to accommodate an upgrade in the testing lib "feels" a bit off... But I will accept the tradeoff to keep the lib up to date. Perhaps we can revisit those changes once Angular is removed.

@@ -7,7 +7,7 @@ import {Runtime} from 'generated/fetch';
import {RuntimeStatus} from 'generated/fetch';
import {RuntimeApi} from 'generated/fetch/api';
import SpyInstance = jest.SpyInstance;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be combined with the import statement below it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I wasn't able to combine two imports.
However, I can do this so that we don't need import SpyInstance = jest.SpyInstance;

let mockGetRuntime: jest.SpyInstance;
let mockCreateRuntime: jest.SpyInstance;
let mockDeleteRuntime: jest.SpyInstance;
let mockStartRuntime: jest.SpyInstance;

Let me know if you like me to make this change.

Copy link
Contributor Author

@aweng98 aweng98 left a comment

Choose a reason for hiding this comment

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

I'm going to merge the PR now. If something is off, please let me know so I will make a follow up PR to address them.

@@ -7,7 +7,7 @@ import {Runtime} from 'generated/fetch';
import {RuntimeStatus} from 'generated/fetch';
import {RuntimeApi} from 'generated/fetch/api';
import SpyInstance = jest.SpyInstance;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I wasn't able to combine two imports.
However, I can do this so that we don't need import SpyInstance = jest.SpyInstance;

let mockGetRuntime: jest.SpyInstance;
let mockCreateRuntime: jest.SpyInstance;
let mockDeleteRuntime: jest.SpyInstance;
let mockStartRuntime: jest.SpyInstance;

Let me know if you like me to make this change.

@aweng98 aweng98 merged commit e605ad1 into master Apr 1, 2021
@aweng98 aweng98 deleted the aw/RW-5959 branch April 1, 2021 22:37
@yonghaoy
Copy link
Collaborator

yonghaoy commented Apr 2, 2021

Hello, yesterday's nightly test fails with error:

    console.error
      Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
          in DemographicSurveyComponent (created by ProfileErrorWrapper)
          in ProfileErrorWrapper (created by ErrorModalWrapper)
          in ErrorModalWrapper (created by AccountCreationSurvey)
          in AccountCreationSurvey (created by SignInImpl)

      206 |       const msgType = message.type() === 'warning' ? 'warn' : message.type();
      207 |       console[msgType](`Page console: "${title}"`);
    > 208 |       console[msgType](...args);
          |                       ^
      209 |       console.log('');
      210 |     } catch (err) {
      211 |       console.error(`❗ "${title}"\nException occurred when getting page console message.\n${err}\n${message.text()}`);

      at jest.test-setup.ts:208:23
          at runMicrotasks (<anonymous>)

    console.log

Is that reverent to this PR?

@aweng98
Copy link
Contributor Author

aweng98 commented Apr 2, 2021

No. It failed here. the runtime status spinner were not excluded in waitWhileLoading function but it should have. I am making a PR to address this.

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.

None yet

5 participants