[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));
});
@@ -14,7 +14,6 @@ import {
createQueryResolverStub,
createResolversStub,
CreateTestRendererParams,
findParentWithType,
replaceHistoryLocation,
wait,
waitForElement,
@@ -344,7 +343,7 @@ it("filter by search", async () => {
const searchField = within(container).getByLabelText("Search by username", {
exact: false,
});
const form = findParentWithType(searchField, "form")!;
const form = within(searchField).getParentByType("form");
await act(async () => {
searchField.props.onChange({
@@ -300,7 +300,7 @@ When disabled, users will have to refresh the page to see new comments.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -324,7 +324,7 @@ When disabled, users will have to refresh the page to see new comments.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -457,7 +457,7 @@ https://domain.com).
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -481,7 +481,7 @@ https://domain.com).
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -525,7 +525,7 @@ https://domain.com).
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -549,7 +549,7 @@ https://domain.com).
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
File diff suppressed because it is too large Load Diff
@@ -259,7 +259,7 @@ reactions, be reported, and be shared.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -283,7 +283,7 @@ reactions, be reported, and be shared.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -373,7 +373,7 @@ reactions, be reported, and be shared.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -397,7 +397,7 @@ reactions, be reported, and be shared.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -505,7 +505,7 @@ Blank spaces at the beginning and the end of a comment will be trimmed.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -529,7 +529,7 @@ Blank spaces at the beginning and the end of a comment will be trimmed.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -782,7 +782,7 @@ moderation panel.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -806,7 +806,7 @@ moderation panel.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -167,7 +167,7 @@ approved by a moderator.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -191,7 +191,7 @@ approved by a moderator.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -226,7 +226,7 @@ approved by a moderator.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -250,7 +250,7 @@ approved by a moderator.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -366,7 +366,7 @@ apply to Staff comments.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -390,7 +390,7 @@ apply to Staff comments.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -520,7 +520,7 @@ If approved by a moderator, the comment will be published.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -544,7 +544,7 @@ If approved by a moderator, the comment will be published.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -686,22 +686,24 @@ improve the API over time.
className="Box-root Flex-root RadioButton-root Flex-flex Flex-alignCenter"
>
<input
checked={false}
checked={true}
className="RadioButton-input"
disabled={false}
id="integrations.perspective.doNotStore-allow"
id="integrations.perspective.doNotStore-true"
name="integrations.perspective.doNotStore"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
htmlFor="integrations.perspective.doNotStore-allow"
htmlFor="integrations.perspective.doNotStore-true"
>
Allow
<span>
Allow
</span>
</label>
</div>
<div
@@ -711,19 +713,21 @@ improve the API over time.
checked={false}
className="RadioButton-input"
disabled={false}
id="integrations.perspective.doNotStore-dontAllow"
id="integrations.perspective.doNotStore-false"
name="integrations.perspective.doNotStore"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
htmlFor="integrations.perspective.doNotStore-dontAllow"
htmlFor="integrations.perspective.doNotStore-false"
>
Don't allow
<span>
Don't allow
</span>
</label>
</div>
</div>
@@ -894,7 +898,7 @@ If approved by a moderator, the comment will be published.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
value="true"
/>
<label
className="RadioButton-label"
@@ -918,7 +922,7 @@ If approved by a moderator, the comment will be published.
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
value="false"
/>
<label
className="RadioButton-label"
@@ -1,6 +1,7 @@
import { pureMerge } from "coral-common/utils";
import { GQLResolver } from "coral-framework/schema";
import {
act,
createResolversStub,
CreateTestRendererParams,
replaceHistoryLocation,
@@ -84,20 +85,24 @@ it("change custom css", async () => {
const customCSSField = within(advancedContainer).getByLabelText("Custom CSS");
// Let's change the customCSS field.
customCSSField.props.onChange("./custom.css");
act(() => customCSSField.props.onChange("./custom.css"));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(customCSSField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(customCSSField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(customCSSField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -128,16 +133,20 @@ it("remove custom css", async () => {
const customCSSField = within(advancedContainer).getByLabelText("Custom CSS");
// Let's change the customCSS field.
customCSSField.props.onChange("");
act(() => customCSSField.props.onChange(""));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Wait for submission to be finished
await wait(() => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
await act(async () => {
await wait(() => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
});
});
});
@@ -191,20 +200,24 @@ it("change permitted domains to be empty", async () => {
);
// Let's change the permitted domains.
permittedDomainsField.props.onChange("");
act(() => permittedDomainsField.props.onChange(""));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(permittedDomainsField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(permittedDomainsField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(permittedDomainsField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -238,22 +251,28 @@ it("change permitted domains to include more domains", async () => {
);
// Let's change the permitted domains.
permittedDomainsField.props.onChange(
"http://localhost:8080, http://localhost:3000"
act(() =>
permittedDomainsField.props.onChange(
"http://localhost:8080, http://localhost:3000"
)
);
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(permittedDomainsField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(permittedDomainsField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(permittedDomainsField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
+141 -128
View File
@@ -1,14 +1,15 @@
import { cloneDeep } from "lodash";
import { ReactTestInstance } from "react-test-renderer";
import sinon from "sinon";
import { pureMerge, timeout } from "coral-common/utils";
import { pureMerge } from "coral-common/utils";
import { GQLResolver } from "coral-framework/schema";
import {
act,
createResolversStub,
CreateTestRendererParams,
limitSnapshotTo,
findParentWithType,
replaceHistoryLocation,
wait,
waitForElement,
within,
} from "coral-framework/testHelpers";
@@ -16,20 +17,6 @@ import {
import create from "../create";
import { settingsWithEmptyAuth, users } from "../fixtures";
/**
* This is depreacted, do not use it anymore.
*
* @deprecated
*/
const deprecatedInputPredicate = (nameOrID: string) => (
n: ReactTestInstance
) => {
return (
[n.props.name, n.props.id].includes(nameOrID) &&
["input", "button"].includes(n.type as string)
);
};
beforeEach(async () => {
replaceHistoryLocation("http://localhost/admin/configure/auth");
});
@@ -94,35 +81,50 @@ it("regenerate sso key", async () => {
},
}),
});
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.sso.enabled"))
.props.onChange({});
const container = within(testRenderer.root).getByTestID("configure-auth-sso");
act(() => {
within(container)
.getByLabelText("Enabled")
.props.onChange({});
});
testRenderer.root
.find(deprecatedInputPredicate("configure-auth-sso-regenerate"))
.props.onClick();
act(() => {
within(container)
.getByText("Regenerate", { selector: "button" })
.props.onClick();
});
await timeout();
expect(
limitSnapshotTo("configure-auth-sso-key", testRenderer.toJSON())
).toMatchSnapshot();
await wait(() =>
expect(within(container).getByLabelText("Key").props.value).toBe(
"==GENERATED_KEY=="
)
);
});
it("prevents admin lock out", async () => {
const { testRenderer } = await createTestRenderer();
const container = within(testRenderer.root).getByTestID(
"configure-auth-local"
);
// Let's disable local auth.
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.local.enabled"))
.props.onChange();
act(() => {
within(container)
.getByLabelText("Enabled")
.props.onChange();
});
// Send form
testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit();
await timeout();
expect(
limitSnapshotTo("configure-auth-submitError", testRenderer.toJSON())
).toMatchSnapshot();
await act(async () =>
findParentWithType(container, "form")!.props.onSubmit()
);
await waitForElement(() =>
within(testRenderer.root).getByText(
"Please enable at least one authentication integration",
{ exact: false }
)
);
});
it("prevents stream lock out", async () => {
@@ -151,36 +153,35 @@ it("prevents stream lock out", async () => {
const stubContinue = sinon.stub().returns(true);
const stubCancel = sinon.stub().returns(false);
const container = within(testRenderer.root).getByTestID(
"configure-auth-local"
);
const streamTarget = within(container).getByLabelText("Comment Stream");
const form = findParentWithType(container, "form")!;
const saveChanges = within(testRenderer.root).getByText("Save Changes", {
selector: "button",
});
try {
window.confirm = stubCancel;
// Let's disable stream target in local auth.
testRenderer.root
.find(
deprecatedInputPredicate("auth.integrations.local.targetFilter.stream")
)
.props.onChange();
act(() => streamTarget.props.onChange());
// Send form
testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit();
await act(async () => await form.props.onSubmit());
// Submit button should not be disabled because we canceled the submit.
expect(
testRenderer.root.findByProps({
"data-testid": "configure-sideBar-saveChanges",
}).props.disabled
).toBe(true);
expect(stubCancel.calledOnce).toBe(true);
wait(() => expect(saveChanges.props.disabled).toBe(true));
wait(() => {
expect(stubCancel.calledOnce).toBe(true);
});
window.confirm = stubContinue;
// Let's enable stream target in local auth.
testRenderer.root
.find(
deprecatedInputPredicate("auth.integrations.local.targetFilter.stream")
)
.props.onChange();
act(() => streamTarget.props.onChange());
// Send form
testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit();
await act(async () => await form.props.onSubmit());
expect(stubContinue.calledOnce).toBe(true);
} finally {
@@ -248,96 +249,108 @@ it("change settings", async () => {
}),
});
const facebookContainer = within(testRenderer.root).getByTestID(
"configure-auth-facebook-container"
);
const facebookEnabled = within(facebookContainer).getByLabelText("Enabled");
const oidcContainer = within(testRenderer.root).getByTestID(
"configure-auth-oidc-container"
);
const oidcEnabled = within(oidcContainer).getByLabelText("Enabled");
const form = findParentWithType(facebookContainer, "form")!;
const saveChanges = within(testRenderer.root).getByText("Save Changes", {
selector: "button",
});
// Let's change some facebook settings.
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.facebook.enabled"))
.props.onChange({});
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.facebook.clientID"))
.props.onChange("myClientID");
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.facebook.clientSecret"))
.props.onChange("myClientSecret");
expect(
limitSnapshotTo("configure-auth-facebook-container", testRenderer.toJSON())
).toMatchSnapshot("enable facebook configure box");
act(() => facebookEnabled.props.onChange({}));
act(() =>
within(facebookContainer)
.getByLabelText("Client ID", { exact: false })
.props.onChange("myClientID")
);
act(() =>
within(facebookContainer)
.getByLabelText("Client secret", { exact: false })
.props.onChange("myClientSecret")
);
// Send form
testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit();
act(() => {
form.props.onSubmit();
});
// Submit button should be disabled.
expect(
testRenderer.root.findByProps({
"data-testid": "configure-sideBar-saveChanges",
}).props.disabled
).toBe(true);
expect(saveChanges.props.disabled).toBe(true);
// Disable other fields while submitting
// We are only testing for one here right now..
expect(
testRenderer.root.find(
deprecatedInputPredicate("auth.integrations.facebook.enabled")
).props.disabled
).toBe(true);
await timeout();
expect(
testRenderer.root.find(
deprecatedInputPredicate("auth.integrations.facebook.enabled")
).props.disabled
).toBe(false);
expect(facebookEnabled.props.disabled).toBe(true);
await act(async () => {
// When submitting finished, the fields become enabled again.
await wait(() => expect(facebookEnabled.props.disabled).toBe(false));
});
// Now let's enable oidc
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.oidc.enabled"))
.props.onChange({});
expect(
limitSnapshotTo("configure-auth-oidc-container", testRenderer.toJSON())
).toMatchSnapshot("enable oidc configure box");
act(() => oidcEnabled.props.onChange({}));
expect(() =>
within(oidcContainer).getAllByText("This field is required", {
exact: false,
})
).toThrow();
// Try to submit form, this will give validation error messages.
testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit();
expect(
limitSnapshotTo("configure-auth-oidc-container", testRenderer.toJSON())
).toMatchSnapshot("oidc validation errors");
act(() => {
form.props.onSubmit();
});
within(oidcContainer).getAllByText("This field is required", {
exact: false,
});
// Fill form
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.oidc.name"))
.props.onChange("name");
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.oidc.clientID"))
.props.onChange("clientID");
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.oidc.clientSecret"))
.props.onChange("clientSecret");
testRenderer.root
.find(deprecatedInputPredicate("auth.integrations.oidc.issuer"))
.props.onChange("http://issuer.com");
act(() =>
within(oidcContainer)
.getByLabelText("Provider name", { exact: false })
.props.onChange("name")
);
act(() =>
within(oidcContainer)
.getByLabelText("Client ID", { exact: false })
.props.onChange("clientID")
);
act(() =>
within(oidcContainer)
.getByLabelText("Client secret", { exact: false })
.props.onChange("clientSecret")
);
act(() =>
within(oidcContainer)
.getByLabelText("Issuer", { exact: false })
.props.onChange("http://issuer.com")
);
// Discover the rest.
testRenderer.root
.find(deprecatedInputPredicate("configure-auth-oidc-discover"))
.props.onClick();
await timeout();
await act(
async () =>
await within(oidcContainer)
.getByText("Discover", { selector: "button" })
.props.onClick()
);
// Try to submit again, this should work now.
testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit();
expect(
limitSnapshotTo("configure-auth-oidc-container", testRenderer.toJSON())
).toMatchSnapshot("during submit: oidc without errors");
act(() => {
form.props.onSubmit();
});
// Submit button should be disabled.
expect(saveChanges.props.disabled).toBe(true);
// Disable other fields while submitting
// We are only testing for one here right now..
expect(
testRenderer.root.find(
deprecatedInputPredicate("auth.integrations.oidc.enabled")
).props.disabled
).toBe(true);
await timeout();
expect(
testRenderer.root.find(
deprecatedInputPredicate("auth.integrations.oidc.enabled")
).props.disabled
).toBe(false);
expect(oidcEnabled.props.disabled).toBe(true);
await act(async () => {
// When submitting finished, the fields become enabled again.
await wait(() => expect(oidcEnabled.props.disabled).toBe(false));
});
});
@@ -5,6 +5,7 @@ import { pureMerge } from "coral-common/utils";
import { InvalidRequestError } from "coral-framework/lib/errors";
import { GQLResolver } from "coral-framework/schema";
import {
act,
createResolversStub,
CreateTestRendererParams,
replaceHistoryLocation,
@@ -86,19 +87,23 @@ it("change language", async () => {
const languageField = within(generalContainer).getByLabelText("Language");
// Let's change the language.
languageField.props.onChange("es");
act(() => languageField.props.onChange("es"));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
await act(async () => {
await wait(() => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
});
});
// Wait for client to change language.
@@ -142,23 +147,27 @@ it("change site wide commenting", async () => {
);
// Let's enable it.
offField.props.onChange(offField.props.value.toString());
act(() => offField.props.onChange(offField.props.value.toString()));
// Let's change the content.
contentField.props.onChange("Closing message");
act(() => contentField.props.onChange("Closing message"));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(offField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(offField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(offField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -201,23 +210,29 @@ it("change community guidlines", async () => {
);
// Let's enable it.
onField.props.onChange(onField.props.value.toString());
act(() => onField.props.onChange(onField.props.value.toString()));
// Let's change the content.
contentField.props.onChange("This is the community guidlines summary");
act(() =>
contentField.props.onChange("This is the community guidlines summary")
);
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(onField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(onField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(onField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -248,19 +263,23 @@ it("change closed stream message", async () => {
);
// Let's change the content.
contentField.props.onChange("The stream has been closed");
act(() => contentField.props.onChange("The stream has been closed"));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
await act(async () => {
await wait(() => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
});
});
});
@@ -292,22 +311,26 @@ it("change comment editing time", async () => {
const hoursOption = within(unitField).getByText(/Hours?/);
// Let's turn on and set some invalid values.
valueField.props.onChange({ target: { value: "" } });
act(() => valueField.props.onChange({ target: { value: "" } }));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
expect(
within(generalContainer).queryAllByText("This field is required.").length
).toBe(1);
// Let's change to sth valid.
valueField.props.onChange({ target: { value: "30" } });
unitField.props.onChange({
target: { value: hoursOption.props.value.toString() },
});
act(() => valueField.props.onChange({ target: { value: "30" } }));
act(() =>
unitField.props.onChange({
target: { value: hoursOption.props.value.toString() },
})
);
expect(
within(generalContainer).queryAllByText(
@@ -316,16 +339,20 @@ it("change comment editing time", async () => {
).toBe(0);
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
await act(async () => {
await wait(() => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
});
});
});
@@ -365,14 +392,16 @@ it("change comment length limitations", async () => {
);
// Let's turn on and set some invalid values.
onField.props.onChange(onField.props.value.toString());
minField.props.onChange("invalid");
maxField.props.onChange("-1");
act(() => onField.props.onChange(onField.props.value.toString()));
act(() => minField.props.onChange("invalid"));
act(() => maxField.props.onChange("-1"));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
expect(
within(generalContainer).queryAllByText(
@@ -381,8 +410,8 @@ it("change comment length limitations", async () => {
).toBe(2);
// Make max smaller than min.
minField.props.onChange("1000");
maxField.props.onChange("500");
act(() => minField.props.onChange("1000"));
act(() => maxField.props.onChange("500"));
expect(
within(generalContainer).queryAllByText(
@@ -391,8 +420,8 @@ it("change comment length limitations", async () => {
).toBe(1);
// Let's change to sth valid.
minField.props.onChange("");
maxField.props.onChange("3000");
act(() => minField.props.onChange(""));
act(() => maxField.props.onChange("3000"));
expect(
within(generalContainer).queryAllByText(
@@ -401,9 +430,11 @@ it("change comment length limitations", async () => {
).toBe(0);
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
@@ -411,9 +442,11 @@ it("change comment length limitations", async () => {
expect(maxField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(minField.props.disabled).toBe(false);
expect(maxField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(minField.props.disabled).toBe(false);
expect(maxField.props.disabled).toBe(false);
});
});
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
});
@@ -452,28 +485,34 @@ it("change closing comment streams", async () => {
const daysOption = within(unitField).getByText(/Days?/);
// Let's turn on and set some invalid values.
onField.props.onChange(onField.props.value.toString());
valueField.props.onChange({ target: { value: "" } });
act(() => onField.props.onChange(onField.props.value.toString()));
act(() => valueField.props.onChange({ target: { value: "" } }));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
expect(
within(generalContainer).queryAllByText("This field is required.").length
).toBe(1);
// Let's change to sth valid.
valueField.props.onChange({ target: { value: "30" } });
unitField.props.onChange({
target: { value: daysOption.props.value.toString() },
});
act(() => valueField.props.onChange({ target: { value: "30" } }));
act(() =>
unitField.props.onChange({
target: { value: daysOption.props.value.toString() },
})
);
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
@@ -481,9 +520,11 @@ it("change closing comment streams", async () => {
expect(unitField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(valueField.props.disabled).toBe(false);
expect(unitField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(valueField.props.disabled).toBe(false);
expect(unitField.props.disabled).toBe(false);
});
});
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
});
@@ -507,15 +548,19 @@ it("handle server error", async () => {
);
// Let's change the content.
contentField.props.onChange("The stream has been closed");
act(() => contentField.props.onChange("The stream has been closed"));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Look for internal error being displayed.
await waitForElement(() =>
within(configureContainer).getByText("INTERNAL_ERROR")
);
await act(async () => {
await waitForElement(() =>
within(configureContainer).getByText("INTERNAL_ERROR")
);
});
});
@@ -1,8 +1,10 @@
import { pureMerge } from "coral-common/utils";
import { GQLMODERATION_MODE, GQLResolver } from "coral-framework/schema";
import {
act,
createResolversStub,
CreateTestRendererParams,
findParentWithType,
replaceHistoryLocation,
wait,
waitForElement,
@@ -73,11 +75,7 @@ it("change site wide pre-moderation", async () => {
},
},
});
const {
configureContainer,
moderationContainer,
saveChangesButton,
} = await createTestRenderer({
const { moderationContainer, saveChangesButton } = await createTestRenderer({
resolvers,
});
@@ -87,22 +85,24 @@ it("change site wide pre-moderation", async () => {
)[0];
const onField = within(preModerationContainer).getByLabelText("On");
const form = findParentWithType(preModerationContainer, "form")!;
// Let's enable it.
onField.props.onChange(onField.props.value.toString());
act(() => onField.props.onChange(onField.props.value.toString()));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
form.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(onField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(onField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(onField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -120,11 +120,7 @@ it("change site wide link pre-moderation", async () => {
},
},
});
const {
configureContainer,
moderationContainer,
saveChangesButton,
} = await createTestRenderer({
const { moderationContainer, saveChangesButton } = await createTestRenderer({
resolvers,
});
@@ -134,22 +130,25 @@ it("change site wide link pre-moderation", async () => {
)[0];
const onField = within(preModerationContainer).getByLabelText("On");
const form = findParentWithType(preModerationContainer, "form")!;
// Let's enable it.
onField.props.onChange(onField.props.value.toString());
act(() => onField.props.onChange(onField.props.value.toString()));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
form.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(onField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(onField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(onField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -171,11 +170,9 @@ it("change akismet settings", async () => {
},
},
});
const {
configureContainer,
moderationContainer,
saveChangesButton,
} = await createTestRenderer({ resolvers });
const { moderationContainer, saveChangesButton } = await createTestRenderer({
resolvers,
});
const akismetContainer = within(moderationContainer).getByTestID(
"akismet-config"
@@ -184,41 +181,44 @@ it("change akismet settings", async () => {
const onField = within(akismetContainer).getByLabelText("On");
const keyField = within(akismetContainer).getByLabelText("API key");
const siteField = within(akismetContainer).getByLabelText("Site URL");
const form = findParentWithType(akismetContainer, "form")!;
// Let's turn it on.
onField.props.onChange(onField.props.value.toString());
act(() => onField.props.onChange(onField.props.value.toString()));
expect(saveChangesButton.props.disabled).toBe(false);
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
form.props.onSubmit();
});
expect(
within(akismetContainer).queryAllByText("This field is required.").length
).toBe(2);
// Input valid api key
keyField.props.onChange("my api key");
act(() => keyField.props.onChange("my api key"));
// Input correct site.
siteField.props.onChange("https://coralproject.net");
act(() => siteField.props.onChange("https://coralproject.net"));
expect(within(akismetContainer).queryAllByText("Invalid URL").length).toBe(0);
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
form.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(onField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(onField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(onField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -253,11 +253,9 @@ it("change perspective settings", async () => {
},
},
});
const {
configureContainer,
moderationContainer,
saveChangesButton,
} = await createTestRenderer({ resolvers });
const { moderationContainer, saveChangesButton } = await createTestRenderer({
resolvers,
});
const perspectiveContainer = within(moderationContainer).getByTestID(
"perspective-container"
@@ -272,17 +270,18 @@ it("change perspective settings", async () => {
const endpointField = within(perspectiveContainer).getByLabelText(
"Custom endpoint"
);
const form = findParentWithType(perspectiveContainer, "form")!;
// Let's turn it on.
onField.props.onChange(onField.props.value.toString());
allowField.props.onChange(allowField.props.value.toString());
act(() => onField.props.onChange(onField.props.value.toString()));
act(() => allowField.props.onChange(allowField.props.value.toString()));
expect(saveChangesButton.props.disabled).toBe(false);
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
form.props.onSubmit();
});
expect(
within(perspectiveContainer).queryAllByText("This field is required.")
@@ -290,13 +289,13 @@ it("change perspective settings", async () => {
).toBe(1);
// Input valid api key
keyField.props.onChange("my api key");
act(() => keyField.props.onChange("my api key"));
// Input malformed endpoint.
endpointField.props.onChange("malformed url");
act(() => endpointField.props.onChange("malformed url"));
// Input malformed threshold.
thresholdField.props.onChange("abc");
act(() => thresholdField.props.onChange("abc"));
expect(
within(perspectiveContainer).queryAllByText("This field is required.")
@@ -312,47 +311,51 @@ it("change perspective settings", async () => {
).toBe(1);
// Input correct site.
endpointField.props.onChange("https://custom-endpoint.net");
act(() => endpointField.props.onChange("https://custom-endpoint.net"));
// Input valid threshold.
thresholdField.props.onChange(10);
act(() => thresholdField.props.onChange(10));
expect(
within(perspectiveContainer).queryAllByText("Invalid URL").length
).toBe(0);
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
form.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(onField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(onField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(onField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
expect(resolvers.Mutation!.updateSettings!.calledOnce).toBe(true);
// Use default threshold.
thresholdField.props.onChange("");
act(() => thresholdField.props.onChange(""));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
form.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(onField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(onField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(onField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -1,6 +1,7 @@
import { pureMerge } from "coral-common/utils";
import { GQLResolver } from "coral-framework/schema";
import {
act,
createResolversStub,
CreateTestRendererParams,
replaceHistoryLocation,
@@ -84,18 +85,20 @@ it("change organization name", async () => {
);
// Let's change some organization name.
organizationNameField.props.onChange("");
act(() => organizationNameField.props.onChange(""));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Should show validation error.
within(organizationContainer).getByText("This field is required.");
// Let's change to some valid organization name.
organizationNameField.props.onChange("Coral Test");
act(() => organizationNameField.props.onChange("Coral Test"));
// Should not show validation error.
expect(
@@ -103,17 +106,21 @@ it("change organization name", async () => {
).toBeNull();
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(organizationNameField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(organizationNameField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(organizationNameField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -144,18 +151,20 @@ it("change organization contact email", async () => {
);
// Let's change some organization name.
organizationEmailField.props.onChange("");
act(() => organizationEmailField.props.onChange(""));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Should show validation error.
within(organizationContainer).getByText("This field is required.");
// Let's change to some valid organization name.
organizationEmailField.props.onChange("test@coralproject.net");
act(() => organizationEmailField.props.onChange("test@coralproject.net"));
// Should not show validation error.
expect(
@@ -163,17 +172,21 @@ it("change organization contact email", async () => {
).toBeNull();
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
expect(organizationEmailField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(organizationEmailField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(organizationEmailField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -1,6 +1,7 @@
import { pureMerge } from "coral-common/utils";
import { GQLResolver } from "coral-framework/schema";
import {
act,
createResolversStub,
CreateTestRendererParams,
replaceHistoryLocation,
@@ -90,13 +91,15 @@ it("change banned and suspect words", async () => {
);
// Let's change the wordlist contents.
bannedField.props.onChange("Fuck\nAsshole");
suspectField.props.onChange("idiot\nshame");
act(() => bannedField.props.onChange("Fuck\nAsshole"));
act(() => suspectField.props.onChange("idiot\nshame"));
// Send form
within(configureContainer)
.getByType("form")
.props.onSubmit();
act(() => {
within(configureContainer)
.getByType("form")
.props.onSubmit();
});
// Submit button and text field should be disabled.
expect(saveChangesButton.props.disabled).toBe(true);
@@ -104,9 +107,11 @@ it("change banned and suspect words", async () => {
expect(suspectField.props.disabled).toBe(true);
// Wait for submission to be finished
await wait(() => {
expect(bannedField.props.disabled).toBe(false);
expect(suspectField.props.disabled).toBe(false);
await act(async () => {
await wait(() => {
expect(bannedField.props.disabled).toBe(false);
expect(suspectField.props.disabled).toBe(false);
});
});
// Should have successfully sent with server.
@@ -14,6 +14,7 @@ import {
CreateTestRendererParams,
findParentWithType,
replaceHistoryLocation,
wait,
waitForElement,
waitUntilThrow,
within,
@@ -59,15 +60,22 @@ async function createTestRenderer(
},
});
const container = await waitForElement(() =>
within(testRenderer.root).getByTestID("stories-container")
);
return { testRenderer, container, context };
return await act(async () => {
const container = await waitForElement(() =>
within(testRenderer.root).getByTestID("stories-container")
);
return { testRenderer, container, context };
});
}
it("renders stories", async () => {
const { container } = await createTestRenderer();
expect(within(container).toJSON()).toMatchSnapshot();
await act(async () => {
await wait(() => {
expect(within(container).toJSON()).toMatchSnapshot();
});
});
});
it("renders empty stories", async () => {
@@ -78,7 +86,12 @@ it("renders empty stories", async () => {
},
}),
});
expect(within(container).toJSON()).toMatchSnapshot();
await act(async () => {
await wait(() => {
expect(within(container).toJSON()).toMatchSnapshot();
});
});
});
it("goes to moderation when clicking on title", async () => {
@@ -96,10 +109,15 @@ it("goes to moderation when clicking on title", async () => {
.getByText(story.metadata!.title!)
.props.onClick({ button: 0, preventDefault: noop });
});
// Expect a routing request was made to the right url.
expect(transitionControl.history[0].pathname).toBe(
`/admin/moderate/${story.id}`
);
await act(async () => {
await wait(() => {
expect(transitionControl.history[0].pathname).toBe(
`/admin/moderate/${story.id}`
);
});
});
});
it("filter by status", async () => {
@@ -122,10 +140,13 @@ it("filter by status", async () => {
const selectField = within(container).getByLabelText("Search by status");
const closedOption = within(selectField).getByText("Closed Stories");
await act(async () => {
act(() => {
selectField.props.onChange({
target: { value: closedOption.props.value.toString() },
});
});
await act(async () => {
await waitForElement(() =>
within(container).getByText("could not find any", { exact: false })
);
@@ -185,7 +206,6 @@ it("change story status", async () => {
act(() => {
changeStatusButton.props.onClick();
});
act(() => {
within(popup)
.getByText("Closed", { selector: "button" })
@@ -241,14 +261,21 @@ it("load more", async () => {
}),
});
const loadMore = within(container).getByText("Load More");
await act(async () => {
act(() => {
loadMore.props.onClick();
});
await act(async () => {
// Wait for load more to disappear.
await waitUntilThrow(() => within(container).getByText("Load More"));
});
// Make sure third user was added.
within(container).getByText(stories[2].metadata!.title!);
await act(async () => {
await wait(() => {
// Make sure third user was added.
within(container).getByText(stories[2].metadata!.title!);
});
});
});
it("filter by search", async () => {
@@ -274,11 +301,16 @@ it("filter by search", async () => {
);
const form = findParentWithType(searchField, "form")!;
await act(async () => {
act(() =>
searchField.props.onChange({
target: { value: "search" },
});
})
);
act(() => {
form.props.onSubmit();
});
await act(async () => {
await waitForElement(() =>
within(container).getByText("could not find any", { exact: false })
);
@@ -303,5 +335,10 @@ it("use searchFilter from url", async () => {
"Search by story title",
{ exact: false }
);
expect(searchField.props.value).toBe(searchFilter);
await act(async () => {
await wait(() => {
expect(searchField.props.value).toBe(searchFilter);
});
});
});