[CORL-729] Upgrade Final Form & improve tests (#2735)

* CORL-729 Upgrade final form, fix and improve tests

This is a squashed rebase from these commits:
a300b31c23ab11e5e6f0668bc03ece7697360aaa feat: error on optimisic response warnings during test
dd8a9776865ec41d346e23ae0743d0d4fb0caa21 fix: turn off @typescript-eslint/prefer-regexp-exec rule
b995daacf1722cace60d755e672cb6a3a20d6bc2 feat: mute false warnings in test
e44f9e28307cd63a82c1fb7ac013667dd7b7bc46 fix: wrap remaining tests with act
afbd4329b97f3dbc9f873ea4ff234d98bb651ccf feat: fail when act(async () => ...) without await warnings
51dfb60b7d75411ba2e1a28db33f4aba5cf84de1 feat: fail tests with act warnings
97f93546ed8113e207882411eb4cdb7675b0796c fix: mock window.resizeTo globally in tests
850958b8c4d2fc0aca67ae580296433af223f8ab fix: more tests with act
24c05ab88e9a416e4962acc3f20f2c764ba07657 fix: wrap charCountEditComment test in acts
ed590b82d147470bba74055dc682e6b70d2e76fb fix signInWithEmail
4a2b9402cb6ce9565d99ae1a950eaa422ff603c3 fix: PostCommentFormContainer
815ebe6ef364d954d4bd0a35495934c9d014170b fix: use final form initialize instead of reset and remove obsolete
d3101f2112ed3ffe8d06609620e31e6655d2cf6d Merge branch 'feature/CORL-729-final-form' of https://github.com/coralproject/talk into feature/CORL-729-final-form
a0658da610a5f39b6fae78ffb8dd291b22d54e50 fix: addEmailAddress
60f7fc99a44dfa49dfd401a0ef49c60973b3e8e3 fix: use proper act pattern in renderConfigure.spec.tsx
d66bdfc2245c2b1ee03a1b3a3a56f1d5ba14ddc4 Stop propagation of Modal content click events (#2706)
ec6689594136e22a5b9f05ea284162702dc4955d fix: use proper act pattern in createUsername.spec.tsx
ef239496964a5f9a91ee1c4424ad81537c4f47fe fix: stream configuration
c7e06a0c6aef6b299c41392af81f8a20855028bf fix: user proper act pattern in streamConfiguration
9712e659e394a898500ed649464ff14d4870e589 Merge branch 'feature/CORL-729-final-form' of https://github.com/coralproject/talk into feature/CORL-729-final-form
9e5cfbaf3593615b457055de23f187fa07edd4c4 fix: signIn test
99b44a4a1bbb7ff2cd44c6821ad33b80f90c4a99 fix: user proper act pattern in stories.spec.tsx
ed7c1a92f93ab9aaa85ff92837b0ed21560cb358 fix: user proper act pattern in addEmailAddress
a04b392cb2148b9a24791b062027796c409d053e fix: remove obsolete snapshots
59df67c0f9b9d26c74e2cca7d333f5868b0b202d fix: signUp test
7656f179df95b4cd96b37afbc88a1c3a2944fdf4 fix: use proper act pattern on createPassword
85246fbf1f9ab49ad3a09c11ab79bf537059b548 fix: use correct act() pattern in createUsername.spec.tsx
d5239373a2d1bbed0bfe8c1ca62ef6a70ef5c7d9 fix: the correct way to use act on form submit :-)
d84ecd168354f4acb422a5ddb725fb8faf9c3184 fix: moderation test
d8df62ab1a6486144684ff917c47e6e375ffbe03 fix: reportComment test
2756e3184bb292168e8d34e201f340c3799941e6 fix: auth tests
a28695dbdd313a7bc3dade9ac1f92d6ef0061526 Properly handle final-form actions in tests
2fafc8ea3458c5b15b66f3d65f0947672dd1a516 Update snapshots now that final form isn't overwriting props
1f9bbaec8678a7653124898ba4a2e84ddc1ef243 fix: prevent final form from overwriting field props
f6c66c003d1917db2dcb3f757e8a303266c381fa fix: prevent final form fields overwrite out props
48d1fc7318ee4ba7bf72839127e9a0b1487c1729 chore: rename translation string
728373da5728a4e7c039bd0c3a3cf0037e9f5177 fix: purge relay metadata from request
7cdea925087a6b9b6e318bbb1b31b798be87dc2f fix: radiobuttons
9735bae79222219a81a28d458976a596201b650b chore: revert obsolete checks
0b556e1693584430a5814e81d87b0f233efd1a30 fix: refactor admin configure
b245afc7b196035bcb454e031c966e63c77ce522 fix: implement withForm HOC
5787400051211f5d2e1773d7207f32b66b02a2a1 Update the Configure page form state to properly load form values
8c2af3e22a96a3d2e50e7f06fb45d1fb79cf0c8e Replace form.reset() with setTimeout(form.reset)
27d9c90e3f0166cc2db45db461619be15a3cb950 Update radio buttons and on/off fields to work with final-form updates
b852dd14af85b14ff8e0d2823e1e83bf278b29b9 Replace any on OnSubmit with typed form submission interfaces
f049a70aaf4872825ac3b2aa62dc5cb7f945290a (f) Preliminarily get Coral compiling with latest final-form libraries

* feat: act is now actAndReturn

* fix: print original filename and line number in custom console impl

* feat: trace process warnings

* fix: server warnings about potentially memory leak with too many listeners
This commit is contained in:
Vinh
2019-12-03 01:07:50 +07:00
committed by GitHub
parent 4ee8cf7c96
commit bc27d7fbec
239 changed files with 4993 additions and 10263 deletions
@@ -563,7 +563,7 @@ exports[`successfully sets email 1`] = `
onFocus={[Function]}
placeholder="Email Address"
type="text"
value=""
value="hans@test.com"
/>
</div>
</div>
@@ -589,7 +589,7 @@ exports[`successfully sets email 1`] = `
onFocus={[Function]}
placeholder="Confirm Email Address"
type="text"
value=""
value="hans@test.com"
/>
</div>
</div>
@@ -466,7 +466,7 @@ we require users to create a password.
placeholder="Password"
spellCheck={false}
type="password"
value=""
value="secretpassword"
/>
<div
className="PasswordField-icon"
@@ -362,7 +362,7 @@ exports[`successfully sets username 1`] = `
onFocus={[Function]}
placeholder="Username"
type="text"
value=""
value="hans"
/>
</div>
</div>
@@ -1,6 +1,7 @@
import { pureMerge } from "coral-common/utils";
import { GQLResolver } from "coral-framework/schema";
import {
act,
createResolversStub,
CreateTestRendererParams,
replaceHistoryLocation,
@@ -42,35 +43,50 @@ async function createTestRenderer(
},
});
const container = await waitForElement(() =>
within(testRenderer.root).getByTestID("completeAccountBox")
);
const form = within(container).getByType("form");
const emailAddressField = within(form).getByLabelText("Email Address");
const confirmEmailAddressField = within(form).getByLabelText(
"Confirm Email Address"
);
return await act(async () => {
const container = await waitForElement(() =>
within(testRenderer.root).getByTestID("completeAccountBox")
);
const form = within(container).getByType("form");
const emailAddressField = within(form).getByLabelText("Email Address");
const confirmEmailAddressField = within(form).getByLabelText(
"Confirm Email Address"
);
return {
context,
testRenderer,
form,
root: testRenderer.root,
emailAddressField,
confirmEmailAddressField,
container,
};
return {
context,
testRenderer,
form,
root: testRenderer.root,
emailAddressField,
confirmEmailAddressField,
container,
};
});
}
it("renders addEmailAddress view", async () => {
const { root } = await createTestRenderer();
expect(toJSON(root)).toMatchSnapshot();
await act(async () => {
await wait(() => {
expect(toJSON(root)).toMatchSnapshot();
});
});
});
it("shows error when submitting empty form", async () => {
const { form } = await createTestRenderer();
form.props.onSubmit();
expect(toJSON(form)).toMatchSnapshot();
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(() => {
expect(toJSON(form)).toMatchSnapshot();
});
});
});
it("checks for invalid email", async () => {
@@ -79,19 +95,42 @@ it("checks for invalid email", async () => {
emailAddressField,
confirmEmailAddressField,
} = await createTestRenderer();
emailAddressField.props.onChange({ target: { value: "invalid-email" } });
confirmEmailAddressField.props.onChange({
target: { value: "invalid-confirmation-email" },
act(() =>
emailAddressField.props.onChange({ target: { value: "invalid-email" } })
);
act(() =>
confirmEmailAddressField.props.onChange({
target: { value: "invalid-confirmation-email" },
})
);
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(() => {
expect(toJSON(form)).toMatchSnapshot();
});
});
form.props.onSubmit();
expect(toJSON(form)).toMatchSnapshot();
});
it("accepts valid email", async () => {
const { form, emailAddressField } = await createTestRenderer();
emailAddressField.props.onChange({ target: { value: "hans@test.com" } });
form.props.onSubmit();
expect(toJSON(form)).toMatchSnapshot();
act(() =>
emailAddressField.props.onChange({ target: { value: "hans@test.com" } })
);
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(() => {
expect(toJSON(form)).toMatchSnapshot();
});
});
});
it("shows server error", async () => {
@@ -116,18 +155,25 @@ it("shows server error", async () => {
i => i.type === "button" && i.props.type === "submit"
);
emailAddressField.props.onChange({ target: { value: email } });
confirmEmailAddressField.props.onChange({
target: { value: email },
});
act(() => emailAddressField.props.onChange({ target: { value: email } }));
act(() =>
confirmEmailAddressField.props.onChange({
target: { value: email },
})
);
form.props.onSubmit();
act(() => {
form.props.onSubmit();
});
expect(emailAddressField.props.disabled).toBe(true);
expect(confirmEmailAddressField.props.disabled).toBe(true);
expect(submitButton.props.disabled).toBe(true);
await wait(() => expect(submitButton.props.disabled).toBe(false));
await act(async () => {
await wait(() => {
expect(submitButton.props.disabled).toBe(false);
});
});
expect(toJSON(form)).toMatchSnapshot();
});
@@ -160,17 +206,25 @@ it("successfully sets email", async () => {
i => i.type === "button" && i.props.type === "submit"
);
emailAddressField.props.onChange({ target: { value: email } });
confirmEmailAddressField.props.onChange({
target: { value: email },
});
act(() => emailAddressField.props.onChange({ target: { value: email } }));
act(() =>
confirmEmailAddressField.props.onChange({
target: { value: email },
})
);
form.props.onSubmit();
act(() => {
form.props.onSubmit();
});
expect(emailAddressField.props.disabled).toBe(true);
expect(confirmEmailAddressField.props.disabled).toBe(true);
expect(submitButton.props.disabled).toBe(true);
await wait(() => expect(submitButton.props.disabled).toBe(false));
await act(async () => {
await wait(() => {
expect(submitButton.props.disabled).toBe(false);
});
});
expect(toJSON(form)).toMatchSnapshot();
expect(resolvers.Mutation!.setEmail!.called).toBe(true);
@@ -1,6 +1,7 @@
import { pureMerge } from "coral-common/utils";
import { GQLResolver } from "coral-framework/schema";
import {
act,
createResolversStub,
CreateTestRendererParams,
replaceHistoryLocation,
@@ -42,50 +43,71 @@ async function createTestRenderer(
},
});
const container = await waitForElement(() =>
within(testRenderer.root).getByTestID("completeAccountBox")
);
const form = within(container).getByType("form");
const passwordField = within(form).getByLabelText("Password");
return await act(async () => {
const container = await waitForElement(() =>
within(testRenderer.root).getByTestID("completeAccountBox")
);
const form = within(container).getByType("form");
const passwordField = within(form).getByLabelText("Password");
return {
context,
testRenderer,
form,
root: testRenderer.root,
passwordField,
container,
};
return {
context,
testRenderer,
form,
root: testRenderer.root,
passwordField,
container,
};
});
}
it("renders createPassword view", async () => {
const { root } = await createTestRenderer();
expect(toJSON(root)).toMatchSnapshot();
await act(async () => {
await wait(async () => {
expect(toJSON(root)).toMatchSnapshot();
});
});
});
it("shows error when submitting empty form", async () => {
const { form } = await createTestRenderer();
form.props.onSubmit();
expect(toJSON(form)).toMatchSnapshot();
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(async () => {
expect(toJSON(form)).toMatchSnapshot();
});
});
});
it("checks for invalid password", async () => {
const { form, passwordField } = await createTestRenderer();
passwordField.props.onChange({ target: { value: "x" } });
form.props.onSubmit();
act(() => passwordField.props.onChange({ target: { value: "x" } }));
act(() => {
form.props.onSubmit();
});
await act(async () => {});
expect(toJSON(form)).toMatchSnapshot();
});
it("shows server error", async () => {
const password = "secretpassword";
const resolvers = createResolversStub<GQLResolver>({
Mutation: {
setPassword: () => {
throw new Error("server error");
const resolvers = await act(async () => {
return createResolversStub<GQLResolver>({
Mutation: {
setPassword: () => {
throw new Error("server error");
},
},
},
});
});
const { form, passwordField } = await createTestRenderer({
resolvers,
muteNetworkErrors: true,
@@ -94,33 +116,38 @@ it("shows server error", async () => {
i => i.type === "button" && i.props.type === "submit"
);
passwordField.props.onChange({ target: { value: password } });
act(() => passwordField.props.onChange({ target: { value: password } }));
form.props.onSubmit();
act(() => {
form.props.onSubmit();
});
expect(passwordField.props.disabled).toBe(true);
expect(submitButton.props.disabled).toBe(true);
await wait(() => expect(submitButton.props.disabled).toBe(false));
await act(async () => {
await wait(() => expect(submitButton.props.disabled).toBe(false));
});
expect(toJSON(form)).toMatchSnapshot();
});
it("successfully sets password", async () => {
const password = "secretpassword";
const resolvers = createResolversStub<GQLResolver>({
Mutation: {
setPassword: ({ variables }) => {
expectAndFail(variables).toEqual({
password,
});
return {
user: {
id: "me",
profiles: [],
},
};
const resolvers = await act(async () => {
return createResolversStub<GQLResolver>({
Mutation: {
setPassword: ({ variables }) => {
expectAndFail(variables).toEqual({
password,
});
return {
user: {
id: "me",
profiles: [],
},
};
},
},
},
});
});
const { form, passwordField } = await createTestRenderer({
resolvers,
@@ -129,14 +156,17 @@ it("successfully sets password", async () => {
i => i.type === "button" && i.props.type === "submit"
);
passwordField.props.onChange({ target: { value: password } });
act(() => passwordField.props.onChange({ target: { value: password } }));
form.props.onSubmit();
act(() => {
form.props.onSubmit();
});
expect(passwordField.props.disabled).toBe(true);
expect(submitButton.props.disabled).toBe(true);
await wait(() => expect(submitButton.props.disabled).toBe(false));
await act(async () => {
await wait(() => expect(submitButton.props.disabled).toBe(false));
});
expect(toJSON(form)).toMatchSnapshot();
expect(resolvers.Mutation!.setPassword!.called).toBe(true);
});
@@ -1,6 +1,7 @@
import { pureMerge } from "coral-common/utils";
import { GQLResolver } from "coral-framework/schema";
import {
act,
createResolversStub,
CreateTestRendererParams,
replaceHistoryLocation,
@@ -35,38 +36,61 @@ async function createTestRenderer(
}
},
});
const container = await waitForElement(() =>
within(testRenderer.root).getByTestID("completeAccountBox")
);
const form = within(container).getByType("form");
const usernameField = within(form).getByLabelText("Username");
return {
context,
testRenderer,
form,
root: testRenderer.root,
usernameField,
container,
};
return await act(async () => {
const container = await waitForElement(() =>
within(testRenderer.root).getByTestID("completeAccountBox")
);
const form = within(container).getByType("form");
const usernameField = within(form).getByLabelText("Username");
return {
context,
testRenderer,
form,
root: testRenderer.root,
usernameField,
container,
};
});
}
it("renders createUsername view", async () => {
const { root } = await createTestRenderer();
expect(toJSON(root)).toMatchSnapshot();
await act(async () => {
await wait(() => {
expect(toJSON(root)).toMatchSnapshot();
});
});
});
it("shows error when submitting empty form", async () => {
const { form } = await createTestRenderer();
form.props.onSubmit();
expect(toJSON(form)).toMatchSnapshot();
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(() => {
expect(toJSON(form)).toMatchSnapshot();
});
});
});
it("checks for invalid username", async () => {
const { form, usernameField } = await createTestRenderer();
usernameField.props.onChange({ target: { value: "x" } });
form.props.onSubmit();
expect(toJSON(form)).toMatchSnapshot();
act(() => usernameField.props.onChange({ target: { value: "x" } }));
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(() => {
expect(toJSON(form)).toMatchSnapshot();
});
});
});
it("shows server error", async () => {
@@ -86,14 +110,19 @@ it("shows server error", async () => {
i => i.type === "button" && i.props.type === "submit"
);
usernameField.props.onChange({ target: { value: username } });
act(() => usernameField.props.onChange({ target: { value: username } }));
form.props.onSubmit();
act(() => {
form.props.onSubmit();
});
expect(usernameField.props.disabled).toBe(true);
expect(submitButton.props.disabled).toBe(true);
await wait(() => expect(submitButton.props.disabled).toBe(false));
await act(async () => {
await wait(() => {
expect(submitButton.props.disabled).toBe(false);
});
});
expect(toJSON(form)).toMatchSnapshot();
});
@@ -122,14 +151,19 @@ it("successfully sets username", async () => {
i => i.type === "button" && i.props.type === "submit"
);
usernameField.props.onChange({ target: { value: username } });
act(() => usernameField.props.onChange({ target: { value: username } }));
form.props.onSubmit();
act(() => {
form.props.onSubmit();
});
expect(usernameField.props.disabled).toBe(true);
expect(submitButton.props.disabled).toBe(true);
await wait(() => expect(submitButton.props.disabled).toBe(false));
await act(async () => {
await wait(() => {
expect(submitButton.props.disabled).toBe(false);
});
});
expect(toJSON(form)).toMatchSnapshot();
expect(resolvers.Mutation!.setUsername!.called).toBe(true);
});
@@ -49,7 +49,6 @@ async function createTestRenderer(
});
let form: ReactTestInstance;
await act(async () => {
form = await waitForElement(() =>
within(testRenderer.root).getByType("form")
@@ -60,50 +59,96 @@ async function createTestRenderer(
it("renders sign in form", async () => {
const { testRenderer } = await createTestRenderer();
expect(testRenderer.toJSON()).toMatchSnapshot();
await act(async () => {
await wait(() => {
expect(testRenderer.toJSON()).toMatchSnapshot();
});
});
});
it("shows error when submitting empty form", async () => {
const { form } = await createTestRenderer();
form.props.onSubmit();
expect(within(form).toJSON()).toMatchSnapshot();
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(() => {
expect(within(form).toJSON()).toMatchSnapshot();
});
});
});
it("checks for invalid email", async () => {
const { form } = await createTestRenderer();
within(form)
.getByLabelText("Email Address")
.props.onChange({ target: { value: "invalid-email" } });
form.props.onSubmit();
expect(within(form).toJSON()).toMatchSnapshot();
act(() => {
within(form)
.getByLabelText("Email Address")
.props.onChange({ target: { value: "invalid-email" } });
});
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(() => {
expect(within(form).toJSON()).toMatchSnapshot();
});
});
});
it("accepts valid email", async () => {
const { form } = await createTestRenderer();
within(form)
.getByLabelText("Email Address")
.props.onChange({ target: { value: "hans@test.com" } });
form.props.onSubmit();
expect(within(form).toJSON()).toMatchSnapshot();
act(() => {
within(form)
.getByLabelText("Email Address")
.props.onChange({ target: { value: "hans@test.com" } });
});
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(() => {
expect(within(form).toJSON()).toMatchSnapshot();
});
});
});
it("accepts correct password", async () => {
const { form } = await createTestRenderer();
within(form)
.getByLabelText("Password")
.props.onChange({ target: { value: "testtest" } });
form.props.onSubmit();
expect(within(form).toJSON()).toMatchSnapshot();
act(() => {
within(form)
.getByLabelText("Password")
.props.onChange({ target: { value: "testtest" } });
});
act(() => {
form.props.onSubmit();
});
await act(async () => {
await wait(() => {
expect(within(form).toJSON()).toMatchSnapshot();
});
});
});
it("shows server error", async () => {
const { form, context } = await createTestRenderer();
within(form)
.getByLabelText("Email Address")
.props.onChange({ target: { value: "hans@test.com" } });
within(form)
.getByLabelText("Password")
.props.onChange({ target: { value: "testtest" } });
act(() => {
within(form)
.getByLabelText("Email Address")
.props.onChange({ target: { value: "hans@test.com" } });
});
act(() => {
within(form)
.getByLabelText("Password")
.props.onChange({ target: { value: "testtest" } });
});
const error = new Error("Server Error");
const restMock = sinon.mock(context.rest);
@@ -119,24 +164,34 @@ it("shows server error", async () => {
.once()
.throws(error);
form.props.onSubmit();
act(() => {
form.props.onSubmit();
});
const submitButton = within(form).getByText("Sign in with Email", {
selector: "button",
});
expect(submitButton.props.disabled).toBe(true);
await wait(() => expect(submitButton.props.disabled).toBe(false));
await act(async () => {
await wait(() => expect(submitButton.props.disabled).toBe(false));
});
expect(within(form).toJSON()).toMatchSnapshot();
restMock.verify();
});
it("submits form successfully", async () => {
const { form, context } = await createTestRenderer();
within(form)
.getByLabelText("Email Address")
.props.onChange({ target: { value: "hans@test.com" } });
within(form)
.getByLabelText("Password")
.props.onChange({ target: { value: "testtest" } });
act(() => {
within(form)
.getByLabelText("Email Address")
.props.onChange({ target: { value: "hans@test.com" } });
});
act(() => {
within(form)
.getByLabelText("Password")
.props.onChange({ target: { value: "testtest" } });
});
const accessToken = createAccessToken();
@@ -162,6 +217,7 @@ it("submits form successfully", async () => {
selector: "button",
});
expect(submitButton.props.disabled).toBe(true);
await act(async () => {
await wait(() => expect(submitButton.props.disabled).toBe(false));
});