mirror of
https://github.com/wassname/talk.git
synced 2026-09-09 11:38:08 +08:00
[CORL-331] Better tests with types (#2270)
* feat: suspending, banning, now propogation * feat: new mutation api with hooks support * feat: better types in tests and refactor * fix: lint
This commit is contained in:
@@ -22,42 +22,30 @@ const UserStatusChangeContainer: StatelessComponent<Props> = props => {
|
||||
const banUser = useMutation(BanUserMutation);
|
||||
const removeUserBan = useMutation(RemoveUserBanMutation);
|
||||
const [showBanned, setShowBanned] = useState<boolean>(false);
|
||||
const handleBan = useCallback(
|
||||
() => {
|
||||
if (props.user.status.ban.active) {
|
||||
return;
|
||||
}
|
||||
setShowBanned(true);
|
||||
},
|
||||
[props.user, setShowBanned]
|
||||
);
|
||||
const handleRemoveBan = useCallback(
|
||||
() => {
|
||||
if (!props.user.status.ban.active) {
|
||||
return;
|
||||
}
|
||||
removeUserBan({ userID: props.user.id });
|
||||
},
|
||||
[props.user, removeUserBan]
|
||||
);
|
||||
const handleSuspend = useCallback(
|
||||
() => {
|
||||
if (props.user.status.suspension.active) {
|
||||
return;
|
||||
}
|
||||
// TODO: (cvle)
|
||||
},
|
||||
[props.user]
|
||||
);
|
||||
const handleRemoveSuspension = useCallback(
|
||||
() => {
|
||||
if (!props.user.status.suspension.active) {
|
||||
return;
|
||||
}
|
||||
// TODO: (cvle)
|
||||
},
|
||||
[props.user]
|
||||
);
|
||||
const handleBan = useCallback(() => {
|
||||
if (props.user.status.ban.active) {
|
||||
return;
|
||||
}
|
||||
setShowBanned(true);
|
||||
}, [props.user, setShowBanned]);
|
||||
const handleRemoveBan = useCallback(() => {
|
||||
if (!props.user.status.ban.active) {
|
||||
return;
|
||||
}
|
||||
removeUserBan({ userID: props.user.id });
|
||||
}, [props.user, removeUserBan]);
|
||||
const handleSuspend = useCallback(() => {
|
||||
if (props.user.status.suspension.active) {
|
||||
return;
|
||||
}
|
||||
// TODO: (cvle)
|
||||
}, [props.user]);
|
||||
const handleRemoveSuspension = useCallback(() => {
|
||||
if (!props.user.status.suspension.active) {
|
||||
return;
|
||||
}
|
||||
// TODO: (cvle)
|
||||
}, [props.user]);
|
||||
|
||||
if (props.user.role !== GQLUSER_ROLE.COMMENTER) {
|
||||
return (
|
||||
|
||||
@@ -23,8 +23,8 @@ class NavigationWarningContainer extends React.Component<Props> {
|
||||
"You have unsaved input. Are you sure you want to leave this page?"
|
||||
);
|
||||
|
||||
this.removeTransitionHook = props.router.addTransitionHook(
|
||||
() => (this.props.active ? warningMessage : true)
|
||||
this.removeTransitionHook = props.router.addTransitionHook(() =>
|
||||
this.props.active ? warningMessage : true
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -48,12 +48,11 @@ const CustomCSSConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
spellCheck={false}
|
||||
fullWidth
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -49,12 +49,11 @@ const PermittedDomainsConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
spellCheck={false}
|
||||
fullWidth
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import { FormApi } from "final-form";
|
||||
import { RouteProps } from "found";
|
||||
import { merge } from "lodash";
|
||||
import React from "react";
|
||||
import { graphql } from "react-relay";
|
||||
|
||||
import { AdvancedConfigContainer_settings as SettingsData } from "talk-admin/__generated__/AdvancedConfigContainer_settings.graphql";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { withFragmentContainer } from "talk-framework/lib/relay";
|
||||
|
||||
import AdvancedConfig from "../components/AdvancedConfig";
|
||||
@@ -28,7 +28,7 @@ class AdvancedConfigContainer extends React.Component<Props> {
|
||||
}
|
||||
|
||||
private handleOnInitValues = (values: any) => {
|
||||
this.initialValues = merge({}, this.initialValues, values);
|
||||
this.initialValues = pureMerge(this.initialValues, values);
|
||||
};
|
||||
|
||||
public render() {
|
||||
|
||||
@@ -36,12 +36,11 @@ const ClientSecretField: StatelessComponent<Props> = ({
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -41,12 +41,11 @@ const ClientSecretField: StatelessComponent<Props> = ({
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
@@ -55,7 +55,8 @@ const FacebookConfig: StatelessComponent<Props> = ({
|
||||
>
|
||||
<Typography>
|
||||
To enable the integration with Facebook Authentication, you need to
|
||||
create and set up a web application. For more information visit:<br />
|
||||
create and set up a web application. For more information visit:
|
||||
<br />
|
||||
{"https://developers.facebook.com/docs/facebook-login/web"}
|
||||
</Typography>
|
||||
</Localized>
|
||||
|
||||
@@ -53,7 +53,8 @@ const GoogleConfig: StatelessComponent<Props> = ({ disabled, callbackURL }) => (
|
||||
>
|
||||
<Typography>
|
||||
To enable the integration with Google Authentication you need to
|
||||
create and set up a web application. For more information visit:<br />
|
||||
create and set up a web application. For more information visit:
|
||||
<br />
|
||||
{
|
||||
"https://developers.google.com/identity/protocols/OAuth2WebServer#creatingcred"
|
||||
}
|
||||
|
||||
@@ -106,12 +106,11 @@ const OIDCConfig: StatelessComponent<Props> = ({
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
@@ -168,12 +167,11 @@ const OIDCConfig: StatelessComponent<Props> = ({
|
||||
Discover
|
||||
</Button>
|
||||
</Flex>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
@@ -201,12 +199,11 @@ const OIDCConfig: StatelessComponent<Props> = ({
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
@@ -234,12 +231,11 @@ const OIDCConfig: StatelessComponent<Props> = ({
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
@@ -267,12 +263,11 @@ const OIDCConfig: StatelessComponent<Props> = ({
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+3
-2
@@ -1,11 +1,12 @@
|
||||
import { FORM_ERROR, FormApi } from "final-form";
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import { RouteProps } from "found";
|
||||
import { get, merge } from "lodash";
|
||||
import { get } from "lodash";
|
||||
import React from "react";
|
||||
import { graphql } from "react-relay";
|
||||
|
||||
import { AuthConfigContainer_auth as AuthData } from "talk-admin/__generated__/AuthConfigContainer_auth.graphql";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { TalkContext, withContext } from "talk-framework/lib/bootstrap";
|
||||
import {
|
||||
AddSubmitHook,
|
||||
@@ -80,7 +81,7 @@ class AuthConfigContainer extends React.Component<Props> {
|
||||
};
|
||||
|
||||
private handleOnInitValues = (values: any) => {
|
||||
this.initialValues = merge({}, this.initialValues, values);
|
||||
this.initialValues = pureMerge(this.initialValues, values);
|
||||
};
|
||||
|
||||
public render() {
|
||||
|
||||
+5
-6
@@ -46,12 +46,11 @@ const ClosedStreamMessageConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
value={input.value}
|
||||
/>
|
||||
</Suspense>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -72,12 +72,11 @@ const ClosingCommentStreamsConfig: StatelessComponent<Props> = ({
|
||||
value={input.value}
|
||||
disabled={disabled}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -63,12 +63,11 @@ const CommentEditingConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
value={input.value}
|
||||
disabled={disabled}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+10
-12
@@ -97,12 +97,11 @@ const CommentLengthConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
textAlignCenter
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
@@ -148,12 +147,11 @@ const CommentLengthConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
textAlignCenter
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -68,12 +68,11 @@ const GuidelinesConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
value={input.value}
|
||||
/>
|
||||
</Suspense>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -81,12 +81,11 @@ const SitewideCommentingConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
value={input.value}
|
||||
/>
|
||||
</Suspense>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import { FormApi } from "final-form";
|
||||
import { RouteProps } from "found";
|
||||
import { merge } from "lodash";
|
||||
import React from "react";
|
||||
import { graphql } from "react-relay";
|
||||
|
||||
import { GeneralConfigContainer_settings as SettingsData } from "talk-admin/__generated__/GeneralConfigContainer_settings.graphql";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { withFragmentContainer } from "talk-framework/lib/relay";
|
||||
|
||||
import GeneralConfig from "../components/GeneralConfig";
|
||||
@@ -28,7 +28,7 @@ class GeneralConfigContainer extends React.Component<Props> {
|
||||
}
|
||||
|
||||
private handleOnInitValues = (values: any) => {
|
||||
this.initialValues = merge({}, this.initialValues, values);
|
||||
this.initialValues = pureMerge(this.initialValues, values);
|
||||
};
|
||||
|
||||
public render() {
|
||||
|
||||
+5
-6
@@ -39,12 +39,11 @@ const APIKeyField: StatelessComponent<Props> = ({
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -107,12 +107,11 @@ const AkismetConfig: StatelessComponent<Props> = ({ disabled }) => {
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+10
-12
@@ -116,12 +116,11 @@ const PerspectiveConfig: StatelessComponent<Props> = ({ disabled }) => {
|
||||
placeholder={TOXICITY_DEFAULT.toString()}
|
||||
textAlignCenter
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
@@ -197,12 +196,11 @@ const PerspectiveConfig: StatelessComponent<Props> = ({ disabled }) => {
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import { FormApi } from "final-form";
|
||||
import { RouteProps } from "found";
|
||||
import { merge } from "lodash";
|
||||
import React from "react";
|
||||
import { graphql } from "react-relay";
|
||||
|
||||
import { ModerationConfigContainer_settings as SettingsData } from "talk-admin/__generated__/ModerationConfigContainer_settings.graphql";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { withFragmentContainer } from "talk-framework/lib/relay";
|
||||
|
||||
import ModerationConfig from "../components/ModerationConfig";
|
||||
@@ -28,7 +28,7 @@ class ModerationConfigContainer extends React.Component<Props> {
|
||||
}
|
||||
|
||||
private handleOnInitValues = (values: any) => {
|
||||
this.initialValues = merge({}, this.initialValues, values);
|
||||
this.initialValues = pureMerge(this.initialValues, values);
|
||||
};
|
||||
|
||||
public render() {
|
||||
|
||||
+5
-6
@@ -50,12 +50,11 @@ const OrganizationNameConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
spellCheck={false}
|
||||
fullWidth
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -53,12 +53,11 @@ const OrganizationNameConfig: StatelessComponent<Props> = ({ disabled }) => (
|
||||
spellCheck={false}
|
||||
fullWidth
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import { FormApi } from "final-form";
|
||||
import { RouteProps } from "found";
|
||||
import { merge } from "lodash";
|
||||
import React from "react";
|
||||
import { graphql } from "react-relay";
|
||||
|
||||
import { OrganizationConfigContainer_settings as SettingsData } from "talk-admin/__generated__/OrganizationConfigContainer_settings.graphql";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { withFragmentContainer } from "talk-framework/lib/relay";
|
||||
|
||||
import OrganizationConfig from "../components/OrganizationConfig";
|
||||
@@ -28,7 +28,7 @@ class OrganizationConfigContainer extends React.Component<Props> {
|
||||
}
|
||||
|
||||
private handleOnInitValues = (values: any) => {
|
||||
this.initialValues = merge({}, this.initialValues, values);
|
||||
this.initialValues = pureMerge(this.initialValues, values);
|
||||
};
|
||||
|
||||
public render() {
|
||||
|
||||
+5
-6
@@ -47,12 +47,11 @@ const WordListTextArea: StatelessComponent<Props> = ({
|
||||
autoCapitalize="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import { FormApi } from "final-form";
|
||||
import { RouteProps } from "found";
|
||||
import { merge } from "lodash";
|
||||
import React from "react";
|
||||
import { graphql } from "react-relay";
|
||||
|
||||
import { WordListConfigContainer_settings as SettingsData } from "talk-admin/__generated__/WordListConfigContainer_settings.graphql";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { withFragmentContainer } from "talk-framework/lib/relay";
|
||||
|
||||
import WordListConfig from "../components/WordListConfig";
|
||||
@@ -28,7 +28,7 @@ class WordListConfigContainer extends React.Component<Props> {
|
||||
}
|
||||
|
||||
private handleOnInitValues = (values: any) => {
|
||||
this.initialValues = merge({}, this.initialValues, values);
|
||||
this.initialValues = pureMerge(this.initialValues, values);
|
||||
};
|
||||
|
||||
public render() {
|
||||
|
||||
@@ -44,12 +44,11 @@ const EmailField: StatelessComponent<Props> = props => (
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -47,12 +47,11 @@ const ConfirmEmailField: StatelessComponent<Props> = props => (
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
@@ -44,12 +44,11 @@ const EmailField: StatelessComponent<Props> = props => (
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -53,12 +53,11 @@ const SetPasswordField: StatelessComponent<Props> = props => (
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
+5
-6
@@ -51,12 +51,11 @@ const CreateUsernameField: StatelessComponent<Props> = props => (
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
@@ -64,12 +64,11 @@ const SignInWithEmail: StatelessComponent<SignInWithEmailForm> = props => {
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched &&
|
||||
(meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
@@ -76,13 +76,12 @@ function markPhrasesHTML(
|
||||
return text;
|
||||
}
|
||||
return tokens
|
||||
.map(
|
||||
(token, i) =>
|
||||
// Using our Regexp patterns it returns tokens arranged this way
|
||||
// [STRING_WITH_NO_MATCH, NEW_WORD_DELIMITER, MATCHED_WORD, ...].
|
||||
// This pattern repeats throughout. Next line will mark MATCHED_WORD
|
||||
// and escape all tokens.
|
||||
i % 3 === 2 ? `<mark>${escapeHTML(token)}</mark>` : escapeHTML(token)
|
||||
.map((token, i) =>
|
||||
// Using our Regexp patterns it returns tokens arranged this way
|
||||
// [STRING_WITH_NO_MATCH, NEW_WORD_DELIMITER, MATCHED_WORD, ...].
|
||||
// This pattern repeats throughout. Next line will mark MATCHED_WORD
|
||||
// and escape all tokens.
|
||||
i % 3 === 2 ? `<mark>${escapeHTML(token)}</mark>` : escapeHTML(token)
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createAccessToken,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
@@ -12,39 +13,37 @@ import {
|
||||
import create from "../create";
|
||||
import { emptyModerationQueues, settings, users } from "../fixtures";
|
||||
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
customResolver: any = {},
|
||||
options: { muteNetworkErrors?: boolean; logNetwork?: boolean } = {}
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
replaceHistoryLocation("http://localhost/admin/login");
|
||||
const resolvers = {
|
||||
...customResolver,
|
||||
Query: {
|
||||
...customResolver.Query,
|
||||
moderationQueues: sinon.stub().returns(emptyModerationQueues),
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(customResolver, "Query.settings"))),
|
||||
viewer: sinon
|
||||
.stub()
|
||||
.returns(
|
||||
merge(
|
||||
{ ...users.admins[0], email: "", username: "", profiles: [] },
|
||||
get(customResolver, "Query.viewer")
|
||||
)
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
const { testRenderer, context } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: options.logNetwork,
|
||||
muteNetworkErrors: options.muteNetworkErrors,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
email: "",
|
||||
username: "",
|
||||
profiles: [],
|
||||
}),
|
||||
moderationQueues: () => emptyModerationQueues,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue("SIGN_IN", "authView");
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
localRecord.setValue(createAccessToken(), "accessToken");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -62,44 +61,60 @@ it("renders addEmailAddress view", async () => {
|
||||
|
||||
it("renders createUsername view", async () => {
|
||||
const { root } = await createTestRenderer({
|
||||
Query: {
|
||||
viewer: {
|
||||
email: "hans@test.com",
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
email: "hans@test.com",
|
||||
username: "",
|
||||
profiles: [],
|
||||
}),
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
await waitForElement(() => within(root).queryByText("Create Username"));
|
||||
});
|
||||
|
||||
it("renders createPassword view", async () => {
|
||||
const { root } = await createTestRenderer({
|
||||
Query: {
|
||||
viewer: {
|
||||
email: "hans@test.com",
|
||||
username: "hans",
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
moderationQueues: () => emptyModerationQueues,
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
email: "hans@test.com",
|
||||
username: "hans",
|
||||
profiles: [],
|
||||
}),
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
await waitForElement(() => within(root).queryByText("Create Password"));
|
||||
});
|
||||
|
||||
it("do not render createPassword view when local auth is disabled", async () => {
|
||||
await createTestRenderer({
|
||||
Query: {
|
||||
viewer: {
|
||||
email: "hans@test.com",
|
||||
username: "hans",
|
||||
},
|
||||
settings: {
|
||||
auth: {
|
||||
integrations: {
|
||||
local: {
|
||||
enabled: false,
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
email: "hans@test.com",
|
||||
username: "hans",
|
||||
profiles: [],
|
||||
}),
|
||||
settings: () =>
|
||||
pureMerge<typeof settings>(settings, {
|
||||
auth: {
|
||||
integrations: {
|
||||
local: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
await wait(() =>
|
||||
@@ -111,13 +126,16 @@ it("do not render createPassword view when local auth is disabled", async () =>
|
||||
|
||||
it("complete account", async () => {
|
||||
await createTestRenderer({
|
||||
Query: {
|
||||
viewer: {
|
||||
email: "hans@test.com",
|
||||
username: "hans",
|
||||
profiles: [{ __typename: "LocalProfile" }],
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
email: "hans@test.com",
|
||||
username: "hans",
|
||||
profiles: [{ __typename: "LocalProfile" }],
|
||||
}),
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
await wait(() =>
|
||||
expect(window.location.toString()).toBe(
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createAccessToken,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
toJSON,
|
||||
wait,
|
||||
@@ -13,33 +14,37 @@ import {
|
||||
import create from "../create";
|
||||
import { settings, users } from "../fixtures";
|
||||
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
customResolver: any = {},
|
||||
options: { muteNetworkErrors?: boolean; logNetwork?: boolean } = {}
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
replaceHistoryLocation("http://localhost/admin/login");
|
||||
const resolvers = {
|
||||
...customResolver,
|
||||
Query: {
|
||||
...customResolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(customResolver, "Query.settings"))),
|
||||
viewer: sinon.stub().returns({ ...users.admins[0], email: "" }),
|
||||
},
|
||||
};
|
||||
|
||||
const { testRenderer, context } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: options.logNetwork,
|
||||
muteNetworkErrors: options.muteNetworkErrors,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
email: "",
|
||||
}),
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue("ADD_EMAIL_ADDRESS", "authView");
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
localRecord.setValue(createAccessToken(), "accessToken");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const container = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("completeAccountBox")
|
||||
);
|
||||
@@ -94,21 +99,22 @@ it("accepts valid email", async () => {
|
||||
|
||||
it("shows server error", async () => {
|
||||
const email = "hans@test.com";
|
||||
const setEmail = sinon.stub().callsFake((_: any, data: any) => {
|
||||
throw new Error("server error");
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
setEmail: () => {
|
||||
throw new Error("server error");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
form,
|
||||
emailAddressField,
|
||||
confirmEmailAddressField,
|
||||
} = await createTestRenderer(
|
||||
{
|
||||
Mutation: {
|
||||
setEmail,
|
||||
},
|
||||
},
|
||||
{ muteNetworkErrors: true }
|
||||
);
|
||||
} = await createTestRenderer({
|
||||
resolvers,
|
||||
muteNetworkErrors: true,
|
||||
});
|
||||
const submitButton = form.find(
|
||||
i => i.type === "button" && i.props.type === "submit"
|
||||
);
|
||||
@@ -130,27 +136,28 @@ it("shows server error", async () => {
|
||||
|
||||
it("successfully sets email", async () => {
|
||||
const email = "hans@test.com";
|
||||
const setEmail = sinon.stub().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input).toEqual({
|
||||
email,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
});
|
||||
return {
|
||||
user: {
|
||||
id: "me",
|
||||
email,
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
setEmail: ({ variables }) => {
|
||||
expectAndFail(variables).toEqual({
|
||||
email,
|
||||
});
|
||||
return {
|
||||
user: {
|
||||
id: "me",
|
||||
email,
|
||||
},
|
||||
};
|
||||
},
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
form,
|
||||
emailAddressField,
|
||||
confirmEmailAddressField,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
setEmail,
|
||||
},
|
||||
resolvers,
|
||||
});
|
||||
const submitButton = form.find(
|
||||
i => i.type === "button" && i.props.type === "submit"
|
||||
@@ -169,5 +176,5 @@ it("successfully sets email", async () => {
|
||||
await wait(() => expect(submitButton.props.disabled).toBe(false));
|
||||
|
||||
expect(toJSON(form)).toMatchSnapshot();
|
||||
expect(setEmail.called).toBe(true);
|
||||
expect(resolvers.Mutation!.setEmail!.called).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createAccessToken,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
toJSON,
|
||||
wait,
|
||||
@@ -13,33 +14,37 @@ import {
|
||||
import create from "../create";
|
||||
import { settings, users } from "../fixtures";
|
||||
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
customResolver: any = {},
|
||||
options: { muteNetworkErrors?: boolean; logNetwork?: boolean } = {}
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
replaceHistoryLocation("http://localhost/admin/login");
|
||||
const resolvers = {
|
||||
...customResolver,
|
||||
Query: {
|
||||
...customResolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(customResolver, "Query.settings"))),
|
||||
viewer: sinon.stub().returns({ ...users.admins[0], profiles: [] }),
|
||||
},
|
||||
};
|
||||
|
||||
const { testRenderer, context } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: options.logNetwork,
|
||||
muteNetworkErrors: options.muteNetworkErrors,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
profiles: [],
|
||||
}),
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue("CREATE_PASSWORD", "authView");
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
localRecord.setValue(createAccessToken(), "accessToken");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const container = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("completeAccountBox")
|
||||
);
|
||||
@@ -76,17 +81,18 @@ it("checks for invalid password", async () => {
|
||||
|
||||
it("shows server error", async () => {
|
||||
const password = "secretpassword";
|
||||
const setPassword = sinon.stub().callsFake((_: any, data: any) => {
|
||||
throw new Error("server error");
|
||||
});
|
||||
const { form, passwordField } = await createTestRenderer(
|
||||
{
|
||||
Mutation: {
|
||||
setPassword,
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
setPassword: () => {
|
||||
throw new Error("server error");
|
||||
},
|
||||
},
|
||||
{ muteNetworkErrors: true }
|
||||
);
|
||||
});
|
||||
|
||||
const { form, passwordField } = await createTestRenderer({
|
||||
resolvers,
|
||||
muteNetworkErrors: true,
|
||||
});
|
||||
const submitButton = form.find(
|
||||
i => i.type === "button" && i.props.type === "submit"
|
||||
);
|
||||
@@ -104,23 +110,23 @@ it("shows server error", async () => {
|
||||
|
||||
it("successfully sets password", async () => {
|
||||
const password = "secretpassword";
|
||||
const setPassword = sinon.stub().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input).toEqual({
|
||||
password,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
});
|
||||
return {
|
||||
user: {
|
||||
id: "me",
|
||||
profiles: [],
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
setPassword: ({ variables }) => {
|
||||
expectAndFail(variables).toEqual({
|
||||
password,
|
||||
});
|
||||
return {
|
||||
user: {
|
||||
id: "me",
|
||||
profiles: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
},
|
||||
});
|
||||
const { form, passwordField } = await createTestRenderer({
|
||||
Mutation: {
|
||||
setPassword,
|
||||
},
|
||||
resolvers,
|
||||
});
|
||||
const submitButton = form.find(
|
||||
i => i.type === "button" && i.props.type === "submit"
|
||||
@@ -135,5 +141,5 @@ it("successfully sets password", async () => {
|
||||
await wait(() => expect(submitButton.props.disabled).toBe(false));
|
||||
|
||||
expect(toJSON(form)).toMatchSnapshot();
|
||||
expect(setPassword.called).toBe(true);
|
||||
expect(resolvers.Mutation!.setPassword!.called).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createAccessToken,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
toJSON,
|
||||
wait,
|
||||
@@ -14,29 +15,27 @@ import create from "../create";
|
||||
import { settings } from "../fixtures";
|
||||
|
||||
async function createTestRenderer(
|
||||
customResolver: any = {},
|
||||
options: { muteNetworkErrors?: boolean; logNetwork?: boolean } = {}
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
replaceHistoryLocation("http://localhost/admin/login");
|
||||
const resolvers = {
|
||||
...customResolver,
|
||||
Query: {
|
||||
...customResolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(customResolver, "Query.settings"))),
|
||||
},
|
||||
};
|
||||
|
||||
const { testRenderer, context } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: options.logNetwork,
|
||||
muteNetworkErrors: options.muteNetworkErrors,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue("CREATE_USERNAME", "authView");
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
localRecord.setValue(createAccessToken(), "accessToken");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
const container = await waitForElement(() =>
|
||||
@@ -75,17 +74,17 @@ it("checks for invalid username", async () => {
|
||||
|
||||
it("shows server error", async () => {
|
||||
const username = "hans";
|
||||
const setUsername = sinon.stub().callsFake((_: any, data: any) => {
|
||||
throw new Error("server error");
|
||||
});
|
||||
const { form, usernameField } = await createTestRenderer(
|
||||
{
|
||||
Mutation: {
|
||||
setUsername,
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
setUsername: () => {
|
||||
throw new Error("server error");
|
||||
},
|
||||
},
|
||||
{ muteNetworkErrors: true }
|
||||
);
|
||||
});
|
||||
const { form, usernameField } = await createTestRenderer({
|
||||
resolvers,
|
||||
muteNetworkErrors: true,
|
||||
});
|
||||
const submitButton = form.find(
|
||||
i => i.type === "button" && i.props.type === "submit"
|
||||
);
|
||||
@@ -103,24 +102,25 @@ it("shows server error", async () => {
|
||||
|
||||
it("successfully sets username", async () => {
|
||||
const username = "hans";
|
||||
const setUsername = sinon.stub().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input).toEqual({
|
||||
username,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
});
|
||||
return {
|
||||
user: {
|
||||
id: "me",
|
||||
username,
|
||||
},
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
});
|
||||
const { form, usernameField } = await createTestRenderer({
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
setUsername,
|
||||
setUsername: ({ variables }) => {
|
||||
expectAndFail(variables).toEqual({
|
||||
username,
|
||||
});
|
||||
return {
|
||||
user: {
|
||||
id: "me",
|
||||
username,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { form, usernameField } = await createTestRenderer({
|
||||
resolvers,
|
||||
});
|
||||
const submitButton = form.find(
|
||||
i => i.type === "button" && i.props.type === "submit"
|
||||
);
|
||||
@@ -134,5 +134,5 @@ it("successfully sets username", async () => {
|
||||
await wait(() => expect(submitButton.props.disabled).toBe(false));
|
||||
|
||||
expect(toJSON(form)).toMatchSnapshot();
|
||||
expect(setUsername.called).toBe(true);
|
||||
expect(resolvers.Mutation!.setUsername!.called).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import sinon from "sinon";
|
||||
import {
|
||||
GQLResolver,
|
||||
QueryToModerationQueuesResolver,
|
||||
} from "talk-framework/schema";
|
||||
import {
|
||||
createAccessToken,
|
||||
createQueryResolverStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import create from "../create";
|
||||
import {
|
||||
emptyModerationQueues,
|
||||
@@ -13,26 +20,41 @@ import {
|
||||
users,
|
||||
} from "../fixtures";
|
||||
|
||||
const resolvers = {
|
||||
Query: {
|
||||
settings: sinon.stub().returns(settings),
|
||||
moderationQueues: sinon.stub().returns(emptyModerationQueues),
|
||||
comments: sinon.stub().returns(emptyRejectedComments),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
},
|
||||
};
|
||||
const viewer = users.admins[0];
|
||||
|
||||
it("redirect when already logged in", async () => {
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
replaceHistoryLocation("http://localhost/admin/login");
|
||||
create({
|
||||
resolvers,
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
initLocalState: localRecord => {
|
||||
const { testRenderer, context } = create({
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
moderationQueues: createQueryResolverStub<
|
||||
QueryToModerationQueuesResolver
|
||||
>(() => emptyModerationQueues),
|
||||
comments: () => emptyRejectedComments,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
localRecord.setValue(createAccessToken(), "accessToken");
|
||||
localRecord.setValue("SIGN_IN", "authView");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
return { testRenderer, context };
|
||||
}
|
||||
|
||||
it("redirect when already logged in", async () => {
|
||||
await createTestRenderer();
|
||||
await wait(() =>
|
||||
expect(window.location.toString()).toBe(
|
||||
"http://localhost/admin/moderate/reported"
|
||||
@@ -41,14 +63,8 @@ it("redirect when already logged in", async () => {
|
||||
});
|
||||
|
||||
it("redirect to redirectPath when already logged in", async () => {
|
||||
replaceHistoryLocation("http://localhost/admin/login");
|
||||
create({
|
||||
resolvers,
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
await createTestRenderer({
|
||||
initLocalState: localRecord => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
localRecord.setValue(createAccessToken(), "accessToken");
|
||||
localRecord.setValue("/admin/moderate/pending", "redirectPath");
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import { ReactTestRenderer } from "react-test-renderer";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { TalkContext } from "talk-framework/lib/bootstrap";
|
||||
import { LOCAL_ID } from "talk-framework/lib/relay";
|
||||
import { replaceHistoryLocation, wait } from "talk-framework/testHelpers";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { LOCAL_ID, lookup } from "talk-framework/lib/relay";
|
||||
import {
|
||||
GQLResolver,
|
||||
QueryToModerationQueuesResolver,
|
||||
} from "talk-framework/schema";
|
||||
import {
|
||||
createQueryResolverStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import create from "../create";
|
||||
import {
|
||||
@@ -12,39 +19,41 @@ import {
|
||||
settings,
|
||||
} from "../fixtures";
|
||||
|
||||
function createTestRenderer(): {
|
||||
testRenderer: ReactTestRenderer;
|
||||
context: TalkContext;
|
||||
} {
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
replaceHistoryLocation("http://localhost/admin/moderate");
|
||||
const resolvers = {
|
||||
Query: {
|
||||
settings: sinon.stub().returns(settings),
|
||||
moderationQueues: sinon.stub().returns(emptyModerationQueues),
|
||||
comments: sinon.stub().returns(emptyRejectedComments),
|
||||
},
|
||||
};
|
||||
const { testRenderer, context } = create({
|
||||
resolvers,
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
moderationQueues: createQueryResolverStub<
|
||||
QueryToModerationQueuesResolver
|
||||
>(() => emptyModerationQueues),
|
||||
comments: () => emptyRejectedComments,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(false, "loggedIn");
|
||||
localRecord.setValue("SIGN_IN", "authView");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
return { testRenderer, context };
|
||||
}
|
||||
|
||||
it("redirect when not logged in", async () => {
|
||||
const { context } = createTestRenderer();
|
||||
const { context } = await createTestRenderer();
|
||||
await wait(() => {
|
||||
expect(
|
||||
context.relayEnvironment
|
||||
.getStore()
|
||||
.getSource()
|
||||
.get(LOCAL_ID)!.redirectPath
|
||||
).toBe("/admin/moderate/reported");
|
||||
expect(lookup(context.relayEnvironment, LOCAL_ID)!.redirectPath).toBe(
|
||||
"/admin/moderate/reported"
|
||||
);
|
||||
expect(window.location.toString()).toBe("http://localhost/admin/login");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { ReactTestRenderer } from "react-test-renderer";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { TalkContext } from "talk-framework/lib/bootstrap";
|
||||
import { LOCAL_ID } from "talk-framework/lib/relay";
|
||||
import { GQLUSER_ROLE } from "talk-framework/schema";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { LOCAL_ID, lookup } from "talk-framework/lib/relay";
|
||||
import { GQLResolver, GQLUSER_ROLE } from "talk-framework/schema";
|
||||
import {
|
||||
createAccessToken,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
@@ -20,29 +21,32 @@ import {
|
||||
users,
|
||||
} from "../fixtures";
|
||||
|
||||
function createTestRenderer(
|
||||
userDiff: any = {}
|
||||
): {
|
||||
testRenderer: ReactTestRenderer;
|
||||
context: TalkContext;
|
||||
} {
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
replaceHistoryLocation("http://localhost/admin/moderate/reported");
|
||||
const resolvers = {
|
||||
Query: {
|
||||
settings: sinon.stub().returns(settings),
|
||||
moderationQueues: sinon.stub().returns(emptyModerationQueues),
|
||||
comments: sinon.stub().returns(emptyRejectedComments),
|
||||
viewer: sinon.stub().returns({ ...users.admins[0], ...userDiff }),
|
||||
},
|
||||
};
|
||||
const { testRenderer, context } = create({
|
||||
resolvers,
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
moderationQueues: () => emptyModerationQueues,
|
||||
comments: () => emptyRejectedComments,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
localRecord.setValue(createAccessToken(), "accessToken");
|
||||
localRecord.setValue("SIGN_IN", "authView");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
return { testRenderer, context };
|
||||
@@ -51,7 +55,16 @@ function createTestRenderer(
|
||||
it("show restricted screen for commenters and staff", async () => {
|
||||
const restrictedRoles = [GQLUSER_ROLE.COMMENTER, GQLUSER_ROLE.STAFF];
|
||||
for (const role of restrictedRoles) {
|
||||
const { testRenderer } = createTestRenderer({ role });
|
||||
const { testRenderer } = await createTestRenderer({
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
role,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
});
|
||||
const authBox = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("authBox")
|
||||
);
|
||||
@@ -60,8 +73,15 @@ it("show restricted screen for commenters and staff", async () => {
|
||||
});
|
||||
|
||||
it("sign out when clicking on sign in as", async () => {
|
||||
const { context, testRenderer } = createTestRenderer({
|
||||
role: GQLUSER_ROLE.COMMENTER,
|
||||
const { testRenderer, context } = await createTestRenderer({
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
viewer: () =>
|
||||
pureMerge<typeof viewer>(viewer, {
|
||||
role: GQLUSER_ROLE.COMMENTER,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
});
|
||||
const authBox = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("authBox")
|
||||
@@ -81,18 +101,10 @@ it("sign out when clicking on sign in as", async () => {
|
||||
.props.onClick();
|
||||
|
||||
await wait(() => {
|
||||
expect(
|
||||
context.relayEnvironment
|
||||
.getStore()
|
||||
.getSource()
|
||||
.get(LOCAL_ID)!.redirectPath
|
||||
).toBe("/admin/moderate/reported");
|
||||
expect(lookup(context.relayEnvironment, LOCAL_ID)!.redirectPath).toBe(
|
||||
"/admin/moderate/reported"
|
||||
);
|
||||
});
|
||||
|
||||
expect(
|
||||
context.relayEnvironment
|
||||
.getStore()
|
||||
.getSource()
|
||||
.get(LOCAL_ID)!.loggedIn
|
||||
).toBeFalsy();
|
||||
expect(lookup(context.relayEnvironment, LOCAL_ID)!.loggedIn).toBeFalsy();
|
||||
});
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { ReactTestInstance } from "react-test-renderer";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createAccessToken,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
@@ -16,32 +19,34 @@ import {
|
||||
settings,
|
||||
} from "../fixtures";
|
||||
|
||||
const resolvers = {
|
||||
Query: {
|
||||
settings: sinon.stub().returns(settings),
|
||||
moderationQueues: sinon.stub().returns(emptyModerationQueues),
|
||||
comments: sinon.stub().returns(emptyRejectedComments),
|
||||
},
|
||||
};
|
||||
|
||||
const inputPredicate = (name: string) => (n: ReactTestInstance) => {
|
||||
return n.props.name === name && n.props.onChange;
|
||||
};
|
||||
|
||||
async function createTestRenderer() {
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
// deliberately setting to a different route,
|
||||
// it should be smart enough to reroute to /admin/login.
|
||||
replaceHistoryLocation("http://localhost/admin/moderate");
|
||||
|
||||
const { testRenderer, context } = create({
|
||||
resolvers,
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
moderationQueues: () => emptyModerationQueues,
|
||||
comments: () => emptyRejectedComments,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(false, "loggedIn");
|
||||
localRecord.setValue("SIGN_IN", "authView");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const form = await waitForElement(() =>
|
||||
within(testRenderer.root).getByType("form")
|
||||
);
|
||||
@@ -121,11 +126,11 @@ it("shows server error", async () => {
|
||||
|
||||
it("submits form successfully", async () => {
|
||||
const { form, context } = await createTestRenderer();
|
||||
form
|
||||
.find(inputPredicate("email"))
|
||||
within(form)
|
||||
.getByLabelText("Email Address")
|
||||
.props.onChange({ target: { value: "hans@test.com" } });
|
||||
form
|
||||
.find(inputPredicate("password"))
|
||||
within(form)
|
||||
.getByLabelText("Password")
|
||||
.props.onChange({ target: { value: "testtest" } });
|
||||
|
||||
const accessToken = createAccessToken();
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import sinon from "sinon";
|
||||
|
||||
import { LOCAL_ID } from "talk-framework/lib/relay";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { LOCAL_ID, lookup } from "talk-framework/lib/relay";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
@@ -16,26 +20,39 @@ import {
|
||||
users,
|
||||
} from "../fixtures";
|
||||
|
||||
const resolvers = {
|
||||
Query: {
|
||||
settings: sinon.stub().returns(settings),
|
||||
moderationQueues: sinon.stub().returns(emptyModerationQueues),
|
||||
comments: sinon.stub().returns(emptyRejectedComments),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
},
|
||||
};
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
replaceHistoryLocation("http://localhost/admin/moderate/reported");
|
||||
const { testRenderer, context } = create({
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
moderationQueues: () => emptyModerationQueues,
|
||||
comments: () => emptyRejectedComments,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
return { testRenderer, context };
|
||||
}
|
||||
|
||||
it("logs out", async () => {
|
||||
replaceHistoryLocation("http://localhost/admin/moderate");
|
||||
|
||||
const { testRenderer, context } = create({
|
||||
resolvers,
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
initLocalState: localRecord => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
},
|
||||
});
|
||||
const { testRenderer, context } = await createTestRenderer();
|
||||
|
||||
const restMock = sinon.mock(context.rest);
|
||||
restMock
|
||||
@@ -60,11 +77,6 @@ it("logs out", async () => {
|
||||
signOutButton.props.onClick();
|
||||
|
||||
await wait(() => {
|
||||
expect(
|
||||
context.relayEnvironment
|
||||
.getStore()
|
||||
.getSource()
|
||||
.get(LOCAL_ID)!.loggedIn
|
||||
).toBeFalsy();
|
||||
expect(lookup(context.relayEnvironment, LOCAL_ID)!.loggedIn).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { merge } from "lodash";
|
||||
import TestRenderer from "react-test-renderer";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import {
|
||||
GQLResolver,
|
||||
GQLUSER_ROLE,
|
||||
GQLUSER_STATUS,
|
||||
QueryToSettingsResolver,
|
||||
QueryToUsersResolver,
|
||||
QueryToViewerResolver,
|
||||
} from "talk-framework/schema";
|
||||
import {
|
||||
createMutationResolverStub,
|
||||
createQueryResolverStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
findParentWithType,
|
||||
replaceHistoryLocation,
|
||||
waitForElement,
|
||||
@@ -18,11 +18,6 @@ import {
|
||||
within,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import {
|
||||
BanUserMutation,
|
||||
RemoveUserBanMutation,
|
||||
UpdateUserRoleMutation,
|
||||
} from "talk-admin/mutations";
|
||||
import create from "../create";
|
||||
import {
|
||||
communityUsers,
|
||||
@@ -35,29 +30,29 @@ beforeEach(async () => {
|
||||
replaceHistoryLocation("http://localhost/admin/community");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
settings: createQueryResolverStub<QueryToSettingsResolver>(
|
||||
() => settings
|
||||
),
|
||||
users: createQueryResolverStub<QueryToUsersResolver>(variables => {
|
||||
expectAndFail(variables.role).toBeFalsy();
|
||||
return communityUsers;
|
||||
}),
|
||||
viewer: createQueryResolverStub<QueryToViewerResolver>(
|
||||
() => users.admins[0]
|
||||
),
|
||||
...resolver.Query,
|
||||
},
|
||||
};
|
||||
const createTestRenderer = async (
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) => {
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
users: ({ variables }) => {
|
||||
expectAndFail(variables.role).toBeFalsy();
|
||||
return communityUsers;
|
||||
},
|
||||
viewer: () => users.admins[0],
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
const container = await waitForElement(() =>
|
||||
@@ -73,10 +68,12 @@ it("renders community", async () => {
|
||||
|
||||
it("renders empty community", async () => {
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
users: createQueryResolverStub<QueryToUsersResolver>(
|
||||
() => emptyCommunityUsers
|
||||
),
|
||||
resolvers: {
|
||||
Query: {
|
||||
users: createQueryResolverStub<QueryToUsersResolver>(
|
||||
() => emptyCommunityUsers
|
||||
),
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(within(container).toJSON()).toMatchSnapshot();
|
||||
@@ -84,9 +81,9 @@ it("renders empty community", async () => {
|
||||
|
||||
it("filter by role", async () => {
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
users: createQueryResolverStub<QueryToUsersResolver>(
|
||||
(variables, callCount) => {
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
users: ({ variables, callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
return communityUsers;
|
||||
@@ -94,9 +91,9 @@ it("filter by role", async () => {
|
||||
expectAndFail(variables.role).toBe(GQLUSER_ROLE.COMMENTER);
|
||||
return emptyCommunityUsers;
|
||||
}
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const selectField = within(container).getByLabelText("Search by role");
|
||||
@@ -127,21 +124,24 @@ it("can't change viewer role", async () => {
|
||||
|
||||
it("change user role", async () => {
|
||||
const user = users.commenters[0];
|
||||
const updateUserRole = createMutationResolverStub<
|
||||
typeof UpdateUserRoleMutation
|
||||
>(variables => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
userID: user.id,
|
||||
role: GQLUSER_ROLE.STAFF,
|
||||
});
|
||||
const userRecord = merge({}, user, { role: variables.role });
|
||||
return {
|
||||
user: userRecord,
|
||||
};
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateUserRole: ({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
userID: user.id,
|
||||
role: GQLUSER_ROLE.STAFF,
|
||||
});
|
||||
const userRecord = pureMerge<typeof user>(user, {
|
||||
role: variables.role,
|
||||
});
|
||||
return {
|
||||
user: userRecord,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { container } = await createTestRenderer({
|
||||
Mutation: { updateUserRole },
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const userRow = within(container).getByText(user.username!, {
|
||||
@@ -165,29 +165,34 @@ it("change user role", async () => {
|
||||
});
|
||||
|
||||
within(userRow).getByText("Staff");
|
||||
expect(updateUserRole.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateUserRole!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("can't change role as a moderator", async () => {
|
||||
const viewer = users.moderators[0];
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
viewer: createQueryResolverStub<QueryToViewerResolver>(() => viewer),
|
||||
},
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
});
|
||||
expect(() => within(container).getByLabelText("Change role")).toThrow();
|
||||
});
|
||||
|
||||
it("load more", async () => {
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
users: createQueryResolverStub<QueryToUsersResolver>(
|
||||
(variables, callCount) => {
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
users: ({ callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
return {
|
||||
edges: [
|
||||
{ node: users.admins[0], cursor: users.admins[0].createdAt },
|
||||
{
|
||||
node: users.admins[0],
|
||||
cursor: users.admins[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: users.commenters[0],
|
||||
cursor: users.commenters[0].createdAt,
|
||||
@@ -212,9 +217,9 @@ it("load more", async () => {
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
const loadMore = within(container).getByText("Load More");
|
||||
TestRenderer.act(() => {
|
||||
@@ -230,9 +235,9 @@ it("load more", async () => {
|
||||
|
||||
it("filter by search", async () => {
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
users: createQueryResolverStub<QueryToUsersResolver>(
|
||||
(variables, callCount) => {
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
users: ({ variables, callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
return communityUsers;
|
||||
@@ -240,9 +245,9 @@ it("filter by search", async () => {
|
||||
expectAndFail(variables.query).toBe("search");
|
||||
return emptyCommunityUsers;
|
||||
}
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const searchField = within(container).getByLabelText("Search by username", {
|
||||
@@ -264,9 +269,9 @@ it("filter by search", async () => {
|
||||
|
||||
it("filter by status", async () => {
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
users: createQueryResolverStub<QueryToUsersResolver>(
|
||||
(variables, callCount) => {
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
users: ({ variables, callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
return communityUsers;
|
||||
@@ -274,9 +279,9 @@ it("filter by status", async () => {
|
||||
expectAndFail(variables.status).toBe("BANNED");
|
||||
return emptyCommunityUsers;
|
||||
}
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const statusField = within(container).getByLabelText(
|
||||
@@ -314,25 +319,28 @@ it("can't change staff, moderator and admin status", async () => {
|
||||
|
||||
it("ban user", async () => {
|
||||
const user = users.commenters[0];
|
||||
const banUser = createMutationResolverStub<typeof BanUserMutation>(
|
||||
variables => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
userID: user.id,
|
||||
});
|
||||
const userRecord = merge({}, user, {
|
||||
status: {
|
||||
current: user.status.current.concat(GQLUSER_STATUS.BANNED),
|
||||
banned: { active: true },
|
||||
},
|
||||
});
|
||||
return {
|
||||
user: userRecord,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
banUser: ({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
userID: user.id,
|
||||
});
|
||||
const userRecord = pureMerge<typeof user>(user, {
|
||||
status: {
|
||||
current: user.status.current.concat(GQLUSER_STATUS.BANNED),
|
||||
ban: { active: true },
|
||||
},
|
||||
});
|
||||
return {
|
||||
user: userRecord,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { container, testRenderer } = await createTestRenderer({
|
||||
Mutation: { banUser },
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const userRow = within(container).getByText(user.username!, {
|
||||
@@ -368,32 +376,32 @@ it("ban user", async () => {
|
||||
.getByText("Ban User")
|
||||
.props.onClick();
|
||||
within(userRow).getByText("Banned");
|
||||
expect(banUser.called).toBe(true);
|
||||
expect(resolvers.Mutation!.banUser!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("remove user ban", async () => {
|
||||
const user = users.bannedCommenter;
|
||||
const removeUserBan = createMutationResolverStub<
|
||||
typeof RemoveUserBanMutation
|
||||
>(variables => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
userID: user.id,
|
||||
});
|
||||
const userRecord = merge({}, user, {
|
||||
status: {
|
||||
current: user.status.current.filter(s => s !== GQLUSER_STATUS.BANNED),
|
||||
banned: { active: false },
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
removeUserBan: ({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
userID: user.id,
|
||||
});
|
||||
const userRecord = pureMerge<typeof user>(user, {
|
||||
status: {
|
||||
current: user.status.current.filter(
|
||||
s => s !== GQLUSER_STATUS.BANNED
|
||||
),
|
||||
ban: { active: false },
|
||||
},
|
||||
});
|
||||
return {
|
||||
user: userRecord,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
user: userRecord,
|
||||
};
|
||||
});
|
||||
|
||||
const { container } = await createTestRenderer({
|
||||
Mutation: { removeUserBan },
|
||||
},
|
||||
Query: {
|
||||
users: createQueryResolverStub<QueryToUsersResolver>(() => ({
|
||||
users: () => ({
|
||||
edges: [
|
||||
{
|
||||
node: user,
|
||||
@@ -401,10 +409,14 @@ it("remove user ban", async () => {
|
||||
},
|
||||
],
|
||||
pageInfo: { endCursor: null, hasNextPage: false },
|
||||
})),
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const { container } = await createTestRenderer({
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const userRow = within(container).getByText(user.username!, {
|
||||
selector: "tr",
|
||||
});
|
||||
@@ -426,5 +438,5 @@ it("remove user ban", async () => {
|
||||
});
|
||||
|
||||
within(userRow).getByText("Active");
|
||||
expect(removeUserBan.called).toBe(true);
|
||||
expect(resolvers.Mutation!.removeUserBan!.called).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createSinonStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
@@ -16,25 +16,30 @@ beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/advanced");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
},
|
||||
};
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer, context } = create({
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const configureContainer = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("configure-container")
|
||||
);
|
||||
@@ -45,12 +50,13 @@ const createTestRenderer = async (resolver: any = {}) => {
|
||||
"configure-sideBar-saveChanges"
|
||||
);
|
||||
return {
|
||||
context,
|
||||
testRenderer,
|
||||
configureContainer,
|
||||
advancedContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
it("renders configure advanced", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
@@ -58,25 +64,22 @@ it("renders configure advanced", async () => {
|
||||
});
|
||||
|
||||
it("change custom css", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.customCSSURL).toEqual("./custom.css");
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.customCSSURL).toEqual("./custom.css");
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
advancedContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const customCSSField = within(advancedContainer).getByLabelText("Custom CSS");
|
||||
@@ -99,29 +102,26 @@ it("change custom css", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change permitted domains to be empty", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.domains).toEqual([]);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.domains).toEqual([]);
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
advancedContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const permittedDomainsField = within(advancedContainer).getByLabelText(
|
||||
@@ -146,32 +146,29 @@ it("change permitted domains to be empty", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change permitted domains to include more domains", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.domains).toEqual([
|
||||
"localhost:8080",
|
||||
"localhost:3000",
|
||||
]);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.domains).toEqual([
|
||||
"localhost:8080",
|
||||
"localhost:3000",
|
||||
]);
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
advancedContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const permittedDomainsField = within(advancedContainer).getByLabelText(
|
||||
@@ -196,5 +193,5 @@ it("change permitted domains to include more domains", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { ReactTestInstance } from "react-test-renderer";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { timeout } from "talk-common/utils";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createSinonStub,
|
||||
inputPredicate,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
limitSnapshotTo,
|
||||
replaceHistoryLocation,
|
||||
waitForElement,
|
||||
@@ -14,29 +17,44 @@ 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].indexOf(nameOrID) > -1 &&
|
||||
["input", "button"].indexOf(n.type as string) > -1
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/auth");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(
|
||||
merge({}, settingsWithEmptyAuth, get(resolver, "Query.settings"))
|
||||
),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
},
|
||||
};
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer, context } = create({
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settingsWithEmptyAuth,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
@@ -45,8 +63,8 @@ const createTestRenderer = async (resolver: any = {}) => {
|
||||
const authContainer = await waitForElement(() =>
|
||||
within(configureContainer).getByTestID("configure-authContainer")
|
||||
);
|
||||
return { testRenderer, configureContainer, authContainer };
|
||||
};
|
||||
return { context, testRenderer, configureContainer, authContainer };
|
||||
}
|
||||
|
||||
it("renders configure auth", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
@@ -55,32 +73,34 @@ it("renders configure auth", async () => {
|
||||
|
||||
it("regenerate sso key", async () => {
|
||||
const { testRenderer } = await createTestRenderer({
|
||||
Mutation: {
|
||||
regenerateSSOKey: createSinonStub(s =>
|
||||
s.callsFake((_: any, data: any) => {
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
regenerateSSOKey: () => {
|
||||
return {
|
||||
settings: merge({}, settingsWithEmptyAuth, {
|
||||
auth: {
|
||||
integrations: {
|
||||
sso: {
|
||||
key: "==GENERATED_KEY==",
|
||||
keyGeneratedAt: "2018-11-12T23:26:06.239Z",
|
||||
settings: pureMerge<typeof settingsWithEmptyAuth>(
|
||||
settingsWithEmptyAuth,
|
||||
{
|
||||
auth: {
|
||||
integrations: {
|
||||
sso: {
|
||||
key: "==GENERATED_KEY==",
|
||||
keyGeneratedAt: "2018-11-12T23:26:06.239Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
}
|
||||
),
|
||||
};
|
||||
})
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.sso.enabled"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.sso.enabled"))
|
||||
.props.onChange({});
|
||||
|
||||
testRenderer.root
|
||||
.find(inputPredicate("configure-auth-sso-regenerate"))
|
||||
.find(deprecatedInputPredicate("configure-auth-sso-regenerate"))
|
||||
.props.onClick();
|
||||
|
||||
await timeout();
|
||||
@@ -95,7 +115,7 @@ it("prevents admin lock out", async () => {
|
||||
|
||||
// Let's disable local auth.
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.local.enabled"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.local.enabled"))
|
||||
.props.onChange();
|
||||
|
||||
// Send form
|
||||
@@ -109,10 +129,10 @@ it("prevents admin lock out", async () => {
|
||||
it("prevents stream lock out", async () => {
|
||||
let settingsRecord = cloneDeep(settingsWithEmptyAuth);
|
||||
const { testRenderer } = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: createSinonStub(s =>
|
||||
s.callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.auth.integrations.local).toEqual({
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.auth!.integrations!.local).toEqual({
|
||||
enabled: true,
|
||||
allowRegistration: true,
|
||||
targetFilter: {
|
||||
@@ -120,14 +140,13 @@ it("prevents stream lock out", async () => {
|
||||
stream: false,
|
||||
},
|
||||
});
|
||||
settingsRecord = merge({}, settingsRecord, data.input.settings);
|
||||
settingsRecord = pureMerge(settingsRecord, variables.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
const origConfirm = window.confirm;
|
||||
const stubContinue = sinon.stub().returns(true);
|
||||
@@ -137,7 +156,9 @@ it("prevents stream lock out", async () => {
|
||||
window.confirm = stubCancel;
|
||||
// Let's disable stream target in local auth.
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.local.targetFilter.stream"))
|
||||
.find(
|
||||
deprecatedInputPredicate("auth.integrations.local.targetFilter.stream")
|
||||
)
|
||||
.props.onChange();
|
||||
|
||||
// Send form
|
||||
@@ -154,7 +175,9 @@ it("prevents stream lock out", async () => {
|
||||
window.confirm = stubContinue;
|
||||
// Let's enable stream target in local auth.
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.local.targetFilter.stream"))
|
||||
.find(
|
||||
deprecatedInputPredicate("auth.integrations.local.targetFilter.stream")
|
||||
)
|
||||
.props.onChange();
|
||||
|
||||
// Send form
|
||||
@@ -167,83 +190,74 @@ it("prevents stream lock out", async () => {
|
||||
});
|
||||
|
||||
it("change settings", async () => {
|
||||
let settingsRecord = cloneDeep(settingsWithEmptyAuth);
|
||||
const { testRenderer } = await createTestRenderer({
|
||||
Query: {
|
||||
discoverOIDCConfiguration: createSinonStub(s =>
|
||||
s.callsFake((_: any, data: any) => {
|
||||
expectAndFail(data).toEqual({ issuer: "http://issuer.com" });
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
discoverOIDCConfiguration: ({ variables }) => {
|
||||
expectAndFail(variables).toEqual({ issuer: "http://issuer.com" });
|
||||
return {
|
||||
issuer: "http://issuer.com",
|
||||
tokenURL: "http://issuer.com/tokenURL",
|
||||
jwksURI: "http://issuer.com/jwksURI",
|
||||
authorizationURL: "http://issuer.com/authorizationURL",
|
||||
};
|
||||
})
|
||||
),
|
||||
},
|
||||
Mutation: {
|
||||
updateSettings: createSinonStub(
|
||||
s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(
|
||||
data.input.settings.auth.integrations.facebook
|
||||
).toEqual({
|
||||
enabled: true,
|
||||
allowRegistration: true,
|
||||
targetFilter: {
|
||||
admin: true,
|
||||
stream: true,
|
||||
},
|
||||
clientID: "myClientID",
|
||||
clientSecret: "myClientSecret",
|
||||
});
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
}),
|
||||
s =>
|
||||
s.onSecondCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.auth.integrations.oidc).toEqual({
|
||||
enabled: true,
|
||||
allowRegistration: false,
|
||||
targetFilter: {
|
||||
admin: true,
|
||||
stream: true,
|
||||
},
|
||||
name: "name",
|
||||
clientID: "clientID",
|
||||
clientSecret: "clientSecret",
|
||||
issuer: "http://issuer.com",
|
||||
jwksURI: "http://issuer.com/jwksURI",
|
||||
authorizationURL: "http://issuer.com/authorizationURL",
|
||||
tokenURL: "http://issuer.com/tokenURL",
|
||||
});
|
||||
(settingsRecord.auth.integrations.oidc as any) = merge(
|
||||
settingsRecord.auth.integrations.oidc,
|
||||
data.input.configuration
|
||||
);
|
||||
return {
|
||||
integration: settingsRecord.auth.integrations.oidc,
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
updateSettings: ({ variables, callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
expectAndFail(
|
||||
variables.settings.auth!.integrations!.facebook
|
||||
).toEqual({
|
||||
enabled: true,
|
||||
allowRegistration: true,
|
||||
targetFilter: {
|
||||
admin: true,
|
||||
stream: true,
|
||||
},
|
||||
clientID: "myClientID",
|
||||
clientSecret: "myClientSecret",
|
||||
});
|
||||
return {
|
||||
settings: pureMerge(settingsWithEmptyAuth, variables.settings),
|
||||
};
|
||||
default:
|
||||
expectAndFail(
|
||||
variables.settings.auth!.integrations!.oidc
|
||||
).toEqual({
|
||||
enabled: true,
|
||||
allowRegistration: false,
|
||||
targetFilter: {
|
||||
admin: true,
|
||||
stream: true,
|
||||
},
|
||||
name: "name",
|
||||
clientID: "clientID",
|
||||
clientSecret: "clientSecret",
|
||||
issuer: "http://issuer.com",
|
||||
jwksURI: "http://issuer.com/jwksURI",
|
||||
authorizationURL: "http://issuer.com/authorizationURL",
|
||||
tokenURL: "http://issuer.com/tokenURL",
|
||||
});
|
||||
return {
|
||||
settings: pureMerge(settingsWithEmptyAuth, variables.settings),
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
// Let's change some facebook settings.
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.facebook.enabled"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.facebook.enabled"))
|
||||
.props.onChange({});
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.facebook.clientID"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.facebook.clientID"))
|
||||
.props.onChange("myClientID");
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.facebook.clientSecret"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.facebook.clientSecret"))
|
||||
.props.onChange("myClientSecret");
|
||||
expect(
|
||||
limitSnapshotTo("configure-auth-facebook-container", testRenderer.toJSON())
|
||||
@@ -262,18 +276,20 @@ it("change settings", async () => {
|
||||
// Disable other fields while submitting
|
||||
// We are only testing for one here right now..
|
||||
expect(
|
||||
testRenderer.root.find(inputPredicate("auth.integrations.facebook.enabled"))
|
||||
.props.disabled
|
||||
testRenderer.root.find(
|
||||
deprecatedInputPredicate("auth.integrations.facebook.enabled")
|
||||
).props.disabled
|
||||
).toBe(true);
|
||||
await timeout();
|
||||
expect(
|
||||
testRenderer.root.find(inputPredicate("auth.integrations.facebook.enabled"))
|
||||
.props.disabled
|
||||
testRenderer.root.find(
|
||||
deprecatedInputPredicate("auth.integrations.facebook.enabled")
|
||||
).props.disabled
|
||||
).toBe(false);
|
||||
|
||||
// Now let's enable oidc
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.oidc.enabled"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.oidc.enabled"))
|
||||
.props.onChange({});
|
||||
|
||||
expect(
|
||||
@@ -288,21 +304,21 @@ it("change settings", async () => {
|
||||
|
||||
// Fill form
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.oidc.name"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.oidc.name"))
|
||||
.props.onChange("name");
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.oidc.clientID"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.oidc.clientID"))
|
||||
.props.onChange("clientID");
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.oidc.clientSecret"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.oidc.clientSecret"))
|
||||
.props.onChange("clientSecret");
|
||||
testRenderer.root
|
||||
.find(inputPredicate("auth.integrations.oidc.issuer"))
|
||||
.find(deprecatedInputPredicate("auth.integrations.oidc.issuer"))
|
||||
.props.onChange("http://issuer.com");
|
||||
|
||||
// Discover the rest.
|
||||
testRenderer.root
|
||||
.find(inputPredicate("configure-auth-oidc-discover"))
|
||||
.find(deprecatedInputPredicate("configure-auth-oidc-discover"))
|
||||
.props.onClick();
|
||||
await timeout();
|
||||
|
||||
@@ -315,12 +331,14 @@ it("change settings", async () => {
|
||||
// Disable other fields while submitting
|
||||
// We are only testing for one here right now..
|
||||
expect(
|
||||
testRenderer.root.find(inputPredicate("auth.integrations.oidc.enabled"))
|
||||
.props.disabled
|
||||
testRenderer.root.find(
|
||||
deprecatedInputPredicate("auth.integrations.oidc.enabled")
|
||||
).props.disabled
|
||||
).toBe(true);
|
||||
await timeout();
|
||||
expect(
|
||||
testRenderer.root.find(inputPredicate("auth.integrations.oidc.enabled"))
|
||||
.props.disabled
|
||||
testRenderer.root.find(
|
||||
deprecatedInputPredicate("auth.integrations.oidc.enabled")
|
||||
).props.disabled
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { ERROR_CODES } from "talk-common/errors";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { InvalidRequestError } from "talk-framework/lib/errors";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createSinonStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
@@ -18,27 +18,27 @@ beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/general");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (
|
||||
resolver: any = {},
|
||||
options: { muteNetworkErrors?: boolean } = {}
|
||||
) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
},
|
||||
};
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
muteNetworkErrors: options.muteNetworkErrors,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer, context } = create({
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
@@ -51,12 +51,13 @@ const createTestRenderer = async (
|
||||
"configure-sideBar-saveChanges"
|
||||
);
|
||||
return {
|
||||
context,
|
||||
testRenderer,
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
it("renders configure general", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
@@ -64,28 +65,25 @@ it("renders configure general", async () => {
|
||||
});
|
||||
|
||||
it("change site wide commenting", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.disableCommenting).toEqual({
|
||||
enabled: true,
|
||||
message: "Closing message",
|
||||
});
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.disableCommenting).toEqual({
|
||||
enabled: true,
|
||||
message: "Closing message",
|
||||
});
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const sitewideCommentingContainer = within(generalContainer).getAllByText(
|
||||
@@ -121,34 +119,32 @@ it("change site wide commenting", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change community guidlines", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.communityGuidelines.content).toEqual(
|
||||
"This is the community guidlines summary"
|
||||
);
|
||||
expectAndFail(data.input.settings.communityGuidelines.enabled).toEqual(
|
||||
true
|
||||
);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.communityGuidelines!.content).toEqual(
|
||||
"This is the community guidlines summary"
|
||||
);
|
||||
expectAndFail(variables.settings.communityGuidelines!.enabled).toEqual(
|
||||
true
|
||||
);
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const guidelinesContainer = within(generalContainer).getAllByText(
|
||||
@@ -182,32 +178,27 @@ it("change community guidlines", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change closed stream message", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.closeCommenting.message).toEqual(
|
||||
"The stream has been closed"
|
||||
);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.closeCommenting!.message).toEqual(
|
||||
"The stream has been closed"
|
||||
);
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
} = await createTestRenderer({ resolvers });
|
||||
|
||||
const contentField = within(generalContainer).getByLabelText(
|
||||
"Closed Stream Message"
|
||||
@@ -226,33 +217,28 @@ it("change closed stream message", async () => {
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("change comment editing time", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.editCommentWindowLength).toEqual(
|
||||
108000
|
||||
);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.editCommentWindowLength).toEqual(
|
||||
108000
|
||||
);
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
} = await createTestRenderer({ resolvers });
|
||||
|
||||
const durationFieldset = within(generalContainer).getByText(
|
||||
"Comment Edit Timeframe",
|
||||
@@ -296,34 +282,31 @@ it("change comment editing time", async () => {
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("change comment length limitations", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.charCount).toEqual({
|
||||
enabled: true,
|
||||
min: null,
|
||||
max: 3000,
|
||||
});
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.charCount).toEqual({
|
||||
enabled: true,
|
||||
min: null,
|
||||
max: 3000,
|
||||
});
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const commentLengthContainer = within(generalContainer).getByText(
|
||||
@@ -389,33 +372,28 @@ it("change comment length limitations", async () => {
|
||||
expect(minField.props.disabled).toBe(false);
|
||||
expect(maxField.props.disabled).toBe(false);
|
||||
});
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change closing comment streams", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.closeCommenting.auto).toEqual(true);
|
||||
expectAndFail(data.input.settings.closeCommenting.timeout).toEqual(
|
||||
2592000
|
||||
);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.closeCommenting!.auto).toEqual(true);
|
||||
expectAndFail(variables.settings.closeCommenting!.timeout).toEqual(
|
||||
2592000
|
||||
);
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
} = await createTestRenderer({ resolvers });
|
||||
|
||||
const closingCommentStreamsContainer = within(generalContainer).getByText(
|
||||
"Closing Comment Streams",
|
||||
@@ -464,23 +442,22 @@ it("change closing comment streams", async () => {
|
||||
expect(valueField.props.disabled).toBe(false);
|
||||
expect(unitField.props.disabled).toBe(false);
|
||||
});
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("handle server error", async () => {
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
throw new InvalidRequestError({ code: ERROR_CODES.INTERNAL_ERROR });
|
||||
})
|
||||
);
|
||||
const { configureContainer, generalContainer } = await createTestRenderer(
|
||||
{
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: () => {
|
||||
throw new InvalidRequestError({ code: ERROR_CODES.INTERNAL_ERROR });
|
||||
},
|
||||
},
|
||||
{ muteNetworkErrors: true }
|
||||
);
|
||||
});
|
||||
|
||||
const { configureContainer, generalContainer } = await createTestRenderer({
|
||||
resolvers,
|
||||
muteNetworkErrors: true,
|
||||
});
|
||||
|
||||
const contentField = within(generalContainer).getByLabelText(
|
||||
"Closed Stream Message"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createSinonStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
@@ -16,23 +16,27 @@ beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/moderation");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
},
|
||||
};
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
@@ -50,7 +54,7 @@ const createTestRenderer = async (resolver: any = {}) => {
|
||||
moderationContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
it("renders configure moderation", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
@@ -58,30 +62,25 @@ it("renders configure moderation", async () => {
|
||||
});
|
||||
|
||||
it("change akismet settings", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.integrations.akismet).toEqual({
|
||||
enabled: true,
|
||||
key: "my api key",
|
||||
site: "https://coralproject.net",
|
||||
});
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.integrations!.akismet).toEqual({
|
||||
enabled: true,
|
||||
key: "my api key",
|
||||
site: "https://coralproject.net",
|
||||
});
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
moderationContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
} = await createTestRenderer({ resolvers });
|
||||
|
||||
const akismetContainer = within(moderationContainer).getByText(
|
||||
"Akismet Spam Detection Filter",
|
||||
@@ -137,48 +136,41 @@ it("change akismet settings", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change perspective settings", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(
|
||||
s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.integrations.perspective).toEqual({
|
||||
doNotStore: false,
|
||||
enabled: true,
|
||||
endpoint: "https://custom-endpoint.net",
|
||||
key: "my api key",
|
||||
threshold: 0.1,
|
||||
});
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables, callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
expectAndFail(variables.settings.integrations!.perspective).toEqual(
|
||||
{
|
||||
doNotStore: false,
|
||||
enabled: true,
|
||||
endpoint: "https://custom-endpoint.net",
|
||||
key: "my api key",
|
||||
threshold: 0.1,
|
||||
}
|
||||
);
|
||||
break;
|
||||
default:
|
||||
expectAndFail(
|
||||
variables.settings.integrations!.perspective!.threshold
|
||||
).toBeNull();
|
||||
}
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
}),
|
||||
s =>
|
||||
s.onSecondCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(
|
||||
data.input.settings.integrations.perspective.threshold
|
||||
).toBeNull();
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
moderationContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
} = await createTestRenderer({ resolvers });
|
||||
|
||||
const perspectiveContainer = within(moderationContainer).getByText(
|
||||
"Perspective Toxic Comment Filter",
|
||||
@@ -258,7 +250,7 @@ it("change perspective settings", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.calledOnce).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.calledOnce).toBe(true);
|
||||
|
||||
// Use default threshold.
|
||||
thresholdField.props.onChange("");
|
||||
@@ -278,5 +270,5 @@ it("change perspective settings", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.calledTwice).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.calledTwice).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createSinonStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
@@ -16,23 +16,27 @@ beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/organization");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
},
|
||||
};
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
@@ -50,7 +54,7 @@ const createTestRenderer = async (resolver: any = {}) => {
|
||||
organizationContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
it("renders configure organization", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
@@ -58,28 +62,23 @@ it("renders configure organization", async () => {
|
||||
});
|
||||
|
||||
it("change organization name", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.organization.name).toEqual(
|
||||
"Coral Test"
|
||||
);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.organization!.name).toEqual(
|
||||
"Coral Test"
|
||||
);
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
organizationContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
} = await createTestRenderer({ resolvers });
|
||||
|
||||
const organizationNameField = within(organizationContainer).getByLabelText(
|
||||
"Organization Name"
|
||||
@@ -119,32 +118,27 @@ it("change organization name", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change organization contact email", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.organization.contactEmail).toEqual(
|
||||
"test@coralproject.net"
|
||||
);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.organization!.contactEmail).toEqual(
|
||||
"test@coralproject.net"
|
||||
);
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
organizationContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
} = await createTestRenderer({ resolvers });
|
||||
|
||||
const organizationEmailField = within(organizationContainer).getByLabelText(
|
||||
"Organization Email"
|
||||
@@ -184,5 +178,5 @@ it("change organization contact email", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { GQLUSER_ROLE } from "talk-framework/schema";
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import { GQLResolver, GQLUSER_ROLE } from "talk-framework/schema";
|
||||
import {
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
waitForElement,
|
||||
within,
|
||||
@@ -15,40 +15,43 @@ beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/general");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (
|
||||
resolver: any = {},
|
||||
options: { muteNetworkErrors?: boolean } = {}
|
||||
) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
},
|
||||
};
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
muteNetworkErrors: options.muteNetworkErrors,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
return {
|
||||
testRenderer,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
it("denies access to moderators", async () => {
|
||||
const deniedRoles = [GQLUSER_ROLE.MODERATOR];
|
||||
for (const r of deniedRoles) {
|
||||
const { testRenderer } = await createTestRenderer({
|
||||
Query: {
|
||||
viewer: sinon.stub().returns({ ...users.admins[0], role: r }),
|
||||
},
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
viewer: () => ({ ...viewer, role: r }),
|
||||
},
|
||||
}),
|
||||
});
|
||||
await waitForElement(() =>
|
||||
within(testRenderer.root).getByText("Sign in with a different account")
|
||||
@@ -60,9 +63,11 @@ it("allows access to admins", async () => {
|
||||
const deniedRoles = [GQLUSER_ROLE.ADMIN];
|
||||
for (const r of deniedRoles) {
|
||||
const { testRenderer } = await createTestRenderer({
|
||||
Query: {
|
||||
viewer: sinon.stub().returns({ ...users.admins[0], role: r }),
|
||||
},
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
viewer: () => ({ ...viewer, role: r }),
|
||||
},
|
||||
}),
|
||||
});
|
||||
await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("configure-container")
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import {
|
||||
createSinonStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
within,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import create from "../create";
|
||||
import { settings, users } from "../fixtures";
|
||||
|
||||
@@ -16,23 +16,27 @@ beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/wordList");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
},
|
||||
};
|
||||
const viewer = users.admins[0];
|
||||
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () => viewer,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
@@ -50,7 +54,7 @@ const createTestRenderer = async (resolver: any = {}) => {
|
||||
wordListContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
it("renders configure wordList", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
@@ -58,28 +62,25 @@ it("renders configure wordList", async () => {
|
||||
});
|
||||
|
||||
it("change banned and suspect words", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input.settings.wordList).toEqual({
|
||||
banned: ["Fuck", "Asshole"],
|
||||
suspect: ["idiot", "shame"],
|
||||
});
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const resolvers = createResolversStub<GQLResolver>({
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.wordList).toEqual({
|
||||
banned: ["Fuck", "Asshole"],
|
||||
suspect: ["idiot", "shame"],
|
||||
});
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const {
|
||||
configureContainer,
|
||||
wordListContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const bannedField = within(wordListContainer).getByLabelText(
|
||||
@@ -110,5 +111,5 @@ it("change banned and suspect words", async () => {
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1,67 +1,12 @@
|
||||
import { EventEmitter2 } from "eventemitter2";
|
||||
import { IResolvers } from "graphql-tools";
|
||||
import React from "react";
|
||||
import TestRenderer, { ReactTestRenderer } from "react-test-renderer";
|
||||
import { Environment, RecordProxy, RecordSourceProxy } from "relay-runtime";
|
||||
|
||||
import EntryContainer from "talk-admin/containers/EntryContainer";
|
||||
import { TalkContext, TalkContextProvider } from "talk-framework/lib/bootstrap";
|
||||
import { PostMessageService } from "talk-framework/lib/postMessage";
|
||||
import { RestClient } from "talk-framework/lib/rest";
|
||||
import { createPromisifiedStorage } from "talk-framework/lib/storage";
|
||||
import { createUUIDGenerator } from "talk-framework/testHelpers";
|
||||
import { GQLResolver } from "talk-framework/schema";
|
||||
import {
|
||||
createTestRenderer,
|
||||
CreateTestRendererParams,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import createEnvironment from "./createEnvironment";
|
||||
import createFluentBundle from "./createFluentBundle";
|
||||
import createNodeMock from "./createNodeMock";
|
||||
|
||||
interface CreateParams {
|
||||
logNetwork?: boolean;
|
||||
resolvers?: IResolvers<any, any>;
|
||||
muteNetworkErrors?: boolean;
|
||||
initLocalState?: (
|
||||
local: RecordProxy,
|
||||
source: RecordSourceProxy,
|
||||
environment: Environment
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default function create(params: CreateParams) {
|
||||
const environment = createEnvironment({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: params.logNetwork,
|
||||
resolvers: params.resolvers,
|
||||
muteNetworkErrors: params.muteNetworkErrors,
|
||||
initLocalState: (localRecord, source, env) => {
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, env);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const context: TalkContext = {
|
||||
relayEnvironment: environment,
|
||||
locales: ["en-US"],
|
||||
localeBundles: [createFluentBundle()],
|
||||
localStorage: createPromisifiedStorage(),
|
||||
sessionStorage: createPromisifiedStorage(),
|
||||
rest: new RestClient("http://localhost/api"),
|
||||
postMessage: new PostMessageService(),
|
||||
browserInfo: { ios: false },
|
||||
uuidGenerator: createUUIDGenerator(),
|
||||
eventEmitter: new EventEmitter2({ wildcard: true, maxListeners: 20 }),
|
||||
clearSession: () => Promise.resolve(),
|
||||
};
|
||||
|
||||
let testRenderer: ReactTestRenderer;
|
||||
TestRenderer.act(() => {
|
||||
testRenderer = TestRenderer.create(
|
||||
<TalkContextProvider value={context}>
|
||||
<EntryContainer />
|
||||
</TalkContextProvider>,
|
||||
{ createNodeMock }
|
||||
);
|
||||
});
|
||||
|
||||
return { context, testRenderer: testRenderer! };
|
||||
export default function create(params: CreateTestRendererParams<GQLResolver>) {
|
||||
return createTestRenderer<GQLResolver>("admin", <EntryContainer />, params);
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { IResolvers } from "graphql-tools";
|
||||
import { Environment, RecordProxy, RecordSourceProxy } from "relay-runtime";
|
||||
import { createRelayEnvironment } from "talk-framework/testHelpers";
|
||||
|
||||
interface CreateEnvironmentParams {
|
||||
logNetwork?: boolean;
|
||||
resolvers?: IResolvers<any, any>;
|
||||
muteNetworkErrors?: boolean;
|
||||
initLocalState?: (
|
||||
local: RecordProxy,
|
||||
source: RecordSourceProxy,
|
||||
environment: Environment
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default function createEnvironment(params: CreateEnvironmentParams) {
|
||||
return createRelayEnvironment({
|
||||
network: {
|
||||
logNetwork: params.logNetwork,
|
||||
muteNetworkErrors: params.muteNetworkErrors,
|
||||
resolvers: params.resolvers || {},
|
||||
projectName: "tenant",
|
||||
},
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import path from "path";
|
||||
|
||||
import { createFluentBundle } from "talk-framework/testHelpers";
|
||||
|
||||
export default function create() {
|
||||
return createFluentBundle(
|
||||
"admin",
|
||||
path.resolve(__dirname, "../../../../locales/en-US")
|
||||
);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { noop } from "lodash";
|
||||
import { ReactElement } from "react";
|
||||
|
||||
export default function createNodeMock(element: ReactElement<any>) {
|
||||
if (element.type === "div") {
|
||||
return {
|
||||
innerHtml: "",
|
||||
className: "",
|
||||
focus: noop,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
import { get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import {
|
||||
createSinonStub,
|
||||
GQLResolver,
|
||||
UserToCommentModerationActionHistoryResolver,
|
||||
} from "talk-framework/schema";
|
||||
import {
|
||||
createQueryResolverStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
toJSON,
|
||||
waitForElement,
|
||||
@@ -17,71 +21,73 @@ beforeEach(async () => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/auth");
|
||||
});
|
||||
|
||||
const commentModerationActionHistory = createSinonStub(
|
||||
s => s.throws(),
|
||||
s =>
|
||||
s.withArgs({ first: 5 }).returns({
|
||||
edges: [
|
||||
{
|
||||
node: moderationActions[0],
|
||||
cursor: moderationActions[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: moderationActions[1],
|
||||
cursor: moderationActions[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: moderationActions[1].createdAt,
|
||||
hasNextPage: true,
|
||||
},
|
||||
}),
|
||||
s =>
|
||||
s
|
||||
.withArgs({
|
||||
first: 10,
|
||||
after: moderationActions[1].createdAt,
|
||||
})
|
||||
.returns({
|
||||
edges: [
|
||||
{
|
||||
node: moderationActions[2],
|
||||
cursor: moderationActions[2].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: moderationActions[2].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
})
|
||||
);
|
||||
const viewer = users.admins[0];
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
viewer: sinon.stub().returns({
|
||||
...users.admins[0],
|
||||
commentModerationActionHistory,
|
||||
}),
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
},
|
||||
};
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () =>
|
||||
pureMerge(viewer, {
|
||||
commentModerationActionHistory: createQueryResolverStub<
|
||||
UserToCommentModerationActionHistoryResolver
|
||||
>(({ variables }) => {
|
||||
if (variables.first === 5) {
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: moderationActions[0],
|
||||
cursor: moderationActions[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: moderationActions[1],
|
||||
cursor: moderationActions[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: moderationActions[1].createdAt,
|
||||
hasNextPage: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
expectAndFail(variables).toEqual({
|
||||
first: 10,
|
||||
after: moderationActions[1].createdAt,
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: moderationActions[2],
|
||||
cursor: moderationActions[2].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: moderationActions[2].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
}),
|
||||
}),
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
const { getByTestID } = within(testRenderer.root);
|
||||
await waitForElement(() => getByTestID("decisionHistory-toggle"));
|
||||
return testRenderer;
|
||||
};
|
||||
}
|
||||
|
||||
async function createTestRendererAndOpenPopover() {
|
||||
const testRenderer = await createTestRenderer();
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
import { get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import {
|
||||
createSinonStub,
|
||||
GQLCOMMENT_STATUS,
|
||||
GQLResolver,
|
||||
ModerationQueueToCommentsResolver,
|
||||
MutationToAcceptCommentResolver,
|
||||
MutationToRejectCommentResolver,
|
||||
QueryToCommentResolver,
|
||||
} from "talk-framework/schema";
|
||||
import {
|
||||
createMutationResolverStub,
|
||||
createQueryResolverStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
replaceHistoryLocation,
|
||||
toJSON,
|
||||
waitForElement,
|
||||
@@ -20,43 +29,37 @@ import {
|
||||
users,
|
||||
} from "../fixtures";
|
||||
|
||||
const viewer = users.admins[0];
|
||||
|
||||
beforeEach(async () => {
|
||||
replaceHistoryLocation("http://localhost/admin/moderate");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
moderationQueues: sinon
|
||||
.stub()
|
||||
.returns(
|
||||
merge(
|
||||
{},
|
||||
emptyModerationQueues,
|
||||
get(resolver, "Query.moderationQueues")
|
||||
)
|
||||
),
|
||||
comments:
|
||||
get(resolver, "Query.comments") ||
|
||||
sinon.stub().returns(emptyRejectedComments),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
},
|
||||
};
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () => viewer,
|
||||
moderationQueues: () => emptyModerationQueues,
|
||||
comments: () => emptyRejectedComments,
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
return testRenderer;
|
||||
};
|
||||
}
|
||||
|
||||
describe("navigation bar", () => {
|
||||
it("renders navigation bar (empty queues)", async () => {
|
||||
@@ -78,48 +81,16 @@ describe("reported queue", () => {
|
||||
|
||||
it("renders reported queue with comments", async () => {
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
moderationQueues: {
|
||||
reported: {
|
||||
count: 2,
|
||||
comments: sinon.stub().callsFake(data => {
|
||||
expectAndFail(data).toEqual({ first: 5 });
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: reportedComments[0],
|
||||
cursor: reportedComments[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: reportedComments[1],
|
||||
cursor: reportedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: reportedComments[1].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const { getByTestID } = within(testRenderer.root);
|
||||
await waitForElement(() => getByTestID("moderate-container"));
|
||||
expect(toJSON(getByTestID("moderate-main-container"))).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders reported queue with comments and load more", async () => {
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
moderationQueues: {
|
||||
reported: {
|
||||
count: 2,
|
||||
comments: createSinonStub(
|
||||
s =>
|
||||
s.onFirstCall().callsFake(data => {
|
||||
expectAndFail(data).toEqual({ first: 5 });
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
moderationQueues: () =>
|
||||
pureMerge(emptyModerationQueues, {
|
||||
reported: {
|
||||
count: 2,
|
||||
comments: createQueryResolverStub<
|
||||
ModerationQueueToCommentsResolver
|
||||
>(({ variables }) => {
|
||||
expectAndFail(variables).toEqual({ first: 5 });
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
@@ -133,34 +104,75 @@ describe("reported queue", () => {
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: reportedComments[1].createdAt,
|
||||
hasNextPage: true,
|
||||
},
|
||||
};
|
||||
}),
|
||||
s =>
|
||||
s.onSecondCall().callsFake(data => {
|
||||
expectAndFail(data).toEqual({
|
||||
first: 10,
|
||||
after: reportedComments[1].createdAt,
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: reportedComments[2],
|
||||
cursor: reportedComments[2].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: reportedComments[2].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
})
|
||||
),
|
||||
},
|
||||
}) as any,
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
});
|
||||
const { getByTestID } = within(testRenderer.root);
|
||||
await waitForElement(() => getByTestID("moderate-container"));
|
||||
expect(toJSON(getByTestID("moderate-main-container"))).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders reported queue with comments and load more", async () => {
|
||||
const moderationQueuesStub = pureMerge(emptyModerationQueues, {
|
||||
reported: {
|
||||
count: 2,
|
||||
comments: createQueryResolverStub<ModerationQueueToCommentsResolver>(
|
||||
({ variables, callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
expectAndFail(variables).toEqual({ first: 5 });
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: reportedComments[0],
|
||||
cursor: reportedComments[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: reportedComments[1],
|
||||
cursor: reportedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: reportedComments[1].createdAt,
|
||||
hasNextPage: true,
|
||||
},
|
||||
};
|
||||
default:
|
||||
expectAndFail(variables).toEqual({
|
||||
first: 10,
|
||||
after: reportedComments[1].createdAt,
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: reportedComments[2],
|
||||
cursor: reportedComments[2].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: reportedComments[2].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
) as any,
|
||||
},
|
||||
});
|
||||
|
||||
const testRenderer = await createTestRenderer({
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
moderationQueues: () => moderationQueuesStub,
|
||||
},
|
||||
}),
|
||||
});
|
||||
const moderateContainer = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("moderate-container")
|
||||
);
|
||||
@@ -194,57 +206,62 @@ describe("reported queue", () => {
|
||||
});
|
||||
|
||||
it("accepts comment in reported queue", async () => {
|
||||
const acceptCommentStub = sinon.stub().callsFake((_, data) => {
|
||||
expectAndFail(data).toMatchObject({
|
||||
input: {
|
||||
commentID: reportedComments[0].id,
|
||||
commentRevisionID: reportedComments[0].revision.id,
|
||||
},
|
||||
const acceptCommentStub = createMutationResolverStub<
|
||||
MutationToAcceptCommentResolver
|
||||
>(({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
commentID: reportedComments[0].id,
|
||||
commentRevisionID: reportedComments[0].revision.id,
|
||||
});
|
||||
return {
|
||||
comment: {
|
||||
id: reportedComments[0].id,
|
||||
status: "ACCEPTED",
|
||||
status: GQLCOMMENT_STATUS.ACCEPTED,
|
||||
},
|
||||
moderationQueues: merge({}, emptyModerationQueues, {
|
||||
moderationQueues: pureMerge(emptyModerationQueues, {
|
||||
reported: {
|
||||
count: 1,
|
||||
},
|
||||
}),
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
});
|
||||
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
moderationQueues: {
|
||||
reported: {
|
||||
count: 2,
|
||||
comments: sinon.stub().callsFake(data => {
|
||||
expectAndFail(data).toEqual({ first: 5 });
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: reportedComments[0],
|
||||
cursor: reportedComments[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: reportedComments[1],
|
||||
cursor: reportedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: reportedComments[1].createdAt,
|
||||
hasNextPage: false,
|
||||
const moderationQueuesStub = pureMerge(emptyModerationQueues, {
|
||||
reported: {
|
||||
count: 2,
|
||||
comments: createQueryResolverStub<ModerationQueueToCommentsResolver>(
|
||||
({ variables }) => {
|
||||
expectAndFail(variables).toEqual({ first: 5 });
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: reportedComments[0],
|
||||
cursor: reportedComments[0].createdAt,
|
||||
},
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
node: reportedComments[1],
|
||||
cursor: reportedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: reportedComments[1].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
) as any,
|
||||
},
|
||||
});
|
||||
|
||||
const testRenderer = await createTestRenderer({
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
moderationQueues: () => moderationQueuesStub,
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
acceptComment: acceptCommentStub,
|
||||
},
|
||||
Mutation: {
|
||||
acceptComment: acceptCommentStub,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const testID = `moderate-comment-${reportedComments[0].id}`;
|
||||
@@ -271,57 +288,61 @@ describe("reported queue", () => {
|
||||
});
|
||||
|
||||
it("rejects comment in reported queue", async () => {
|
||||
const rejectCommentStub = sinon.stub().callsFake((_, data) => {
|
||||
expectAndFail(data).toMatchObject({
|
||||
input: {
|
||||
commentID: reportedComments[0].id,
|
||||
commentRevisionID: reportedComments[0].revision.id,
|
||||
},
|
||||
const rejectCommentStub = createMutationResolverStub<
|
||||
MutationToRejectCommentResolver
|
||||
>(({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
commentID: reportedComments[0].id,
|
||||
commentRevisionID: reportedComments[0].revision.id,
|
||||
});
|
||||
return {
|
||||
comment: {
|
||||
id: reportedComments[0].id,
|
||||
status: "REJECTED",
|
||||
status: GQLCOMMENT_STATUS.REJECTED,
|
||||
},
|
||||
moderationQueues: merge({}, emptyModerationQueues, {
|
||||
moderationQueues: pureMerge(emptyModerationQueues, {
|
||||
reported: {
|
||||
count: 1,
|
||||
},
|
||||
}),
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
});
|
||||
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
moderationQueues: {
|
||||
reported: {
|
||||
count: 2,
|
||||
comments: sinon.stub().callsFake(data => {
|
||||
expectAndFail(data).toEqual({ first: 5 });
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: reportedComments[0],
|
||||
cursor: reportedComments[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: reportedComments[1],
|
||||
cursor: reportedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: reportedComments[1].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
moderationQueues: () =>
|
||||
pureMerge(emptyModerationQueues, {
|
||||
reported: {
|
||||
count: 2,
|
||||
comments: createQueryResolverStub<
|
||||
ModerationQueueToCommentsResolver
|
||||
>(({ variables }) => {
|
||||
expectAndFail(variables).toEqual({ first: 5 });
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: reportedComments[0],
|
||||
cursor: reportedComments[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: reportedComments[1],
|
||||
cursor: reportedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: reportedComments[1].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
}) as any,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
rejectComment: rejectCommentStub,
|
||||
},
|
||||
Mutation: {
|
||||
rejectComment: rejectCommentStub,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const testID = `moderate-comment-${reportedComments[0].id}`;
|
||||
@@ -355,30 +376,32 @@ describe("rejected queue", () => {
|
||||
|
||||
it("renders rejected queue with comments", async () => {
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
comments: sinon.stub().callsFake((_, data) => {
|
||||
expectAndFail(data).toEqual({
|
||||
first: 5,
|
||||
status: "REJECTED",
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: rejectedComments[0],
|
||||
cursor: rejectedComments[0].createdAt,
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
comments: ({ variables }) => {
|
||||
expectAndFail(variables).toEqual({
|
||||
first: 5,
|
||||
status: "REJECTED",
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: rejectedComments[0],
|
||||
cursor: rejectedComments[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: rejectedComments[1],
|
||||
cursor: rejectedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: rejectedComments[1].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
{
|
||||
node: rejectedComments[1],
|
||||
cursor: rejectedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: rejectedComments[1].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
const { getByTestID } = within(testRenderer.root);
|
||||
await waitForElement(() => getByTestID("moderate-container"));
|
||||
@@ -387,53 +410,53 @@ describe("rejected queue", () => {
|
||||
|
||||
it("renders rejected queue with comments and load more", async () => {
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
comments: createSinonStub(
|
||||
s =>
|
||||
s.onFirstCall().callsFake((_, data) => {
|
||||
expectAndFail(data).toEqual({
|
||||
first: 5,
|
||||
status: "REJECTED",
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: rejectedComments[0],
|
||||
cursor: rejectedComments[0].createdAt,
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
comments: ({ variables, callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
expectAndFail(variables).toEqual({
|
||||
first: 5,
|
||||
status: GQLCOMMENT_STATUS.REJECTED,
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: rejectedComments[0],
|
||||
cursor: rejectedComments[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: rejectedComments[1],
|
||||
cursor: rejectedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: rejectedComments[1].createdAt,
|
||||
hasNextPage: true,
|
||||
},
|
||||
{
|
||||
node: rejectedComments[1],
|
||||
cursor: rejectedComments[1].createdAt,
|
||||
};
|
||||
default:
|
||||
expectAndFail(variables).toEqual({
|
||||
first: 10,
|
||||
after: rejectedComments[1].createdAt,
|
||||
status: GQLCOMMENT_STATUS.REJECTED,
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: rejectedComments[2],
|
||||
cursor: rejectedComments[2].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: rejectedComments[2].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: rejectedComments[1].createdAt,
|
||||
hasNextPage: true,
|
||||
},
|
||||
};
|
||||
}),
|
||||
s =>
|
||||
s.onSecondCall().callsFake((_, data) => {
|
||||
expectAndFail(data).toEqual({
|
||||
first: 10,
|
||||
after: rejectedComments[1].createdAt,
|
||||
status: "REJECTED",
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: rejectedComments[2],
|
||||
cursor: rejectedComments[2].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: rejectedComments[2].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
})
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const moderateContainer = await waitForElement(() =>
|
||||
@@ -469,55 +492,56 @@ describe("rejected queue", () => {
|
||||
});
|
||||
|
||||
it("accepts comment in rejected queue", async () => {
|
||||
const acceptCommentStub = sinon.stub().callsFake((_, data) => {
|
||||
expectAndFail(data).toMatchObject({
|
||||
input: {
|
||||
commentID: rejectedComments[0].id,
|
||||
commentRevisionID: rejectedComments[0].revision.id,
|
||||
},
|
||||
const acceptCommentStub = createMutationResolverStub<
|
||||
MutationToAcceptCommentResolver
|
||||
>(({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
commentID: rejectedComments[0].id,
|
||||
commentRevisionID: rejectedComments[0].revision.id,
|
||||
});
|
||||
return {
|
||||
comment: {
|
||||
id: rejectedComments[0].id,
|
||||
status: "ACCEPTED",
|
||||
status: GQLCOMMENT_STATUS.ACCEPTED,
|
||||
},
|
||||
moderationQueues: merge({}, emptyModerationQueues, {
|
||||
moderationQueues: pureMerge(emptyModerationQueues, {
|
||||
reported: {
|
||||
count: 1,
|
||||
},
|
||||
}),
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
});
|
||||
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
comments: sinon.stub().callsFake((_, data) => {
|
||||
expectAndFail(data).toEqual({
|
||||
first: 5,
|
||||
status: "REJECTED",
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: rejectedComments[0],
|
||||
cursor: rejectedComments[0].createdAt,
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
comments: ({ variables }) => {
|
||||
expectAndFail(variables).toEqual({
|
||||
first: 5,
|
||||
status: "REJECTED",
|
||||
});
|
||||
return {
|
||||
edges: [
|
||||
{
|
||||
node: rejectedComments[0],
|
||||
cursor: rejectedComments[0].createdAt,
|
||||
},
|
||||
{
|
||||
node: rejectedComments[1],
|
||||
cursor: rejectedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: rejectedComments[1].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
{
|
||||
node: rejectedComments[1],
|
||||
cursor: rejectedComments[1].createdAt,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: rejectedComments[1].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
}),
|
||||
},
|
||||
Mutation: {
|
||||
acceptComment: acceptCommentStub,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
acceptComment: acceptCommentStub,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const testID = `moderate-comment-${rejectedComments[0].id}`;
|
||||
@@ -546,10 +570,12 @@ describe("rejected queue", () => {
|
||||
|
||||
describe("single comment view", () => {
|
||||
const comment = rejectedComments[0];
|
||||
const commentStub = sinon.stub().callsFake((_, data) => {
|
||||
expectAndFail(data).toEqual({ id: comment.id });
|
||||
return reportedComments[0];
|
||||
});
|
||||
const commentStub = createQueryResolverStub<QueryToCommentResolver>(
|
||||
({ variables }) => {
|
||||
expectAndFail(variables).toEqual({ id: comment.id });
|
||||
return reportedComments[0];
|
||||
}
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
replaceHistoryLocation(
|
||||
@@ -559,8 +585,10 @@ describe("single comment view", () => {
|
||||
|
||||
it("renders single comment view", async () => {
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
comment: commentStub,
|
||||
resolvers: {
|
||||
Query: {
|
||||
comment: commentStub,
|
||||
},
|
||||
},
|
||||
});
|
||||
const { getByTestID } = within(testRenderer.root);
|
||||
@@ -571,29 +599,30 @@ describe("single comment view", () => {
|
||||
});
|
||||
|
||||
it("accepts single comment", async () => {
|
||||
const acceptCommentStub = sinon.stub().callsFake((_, data) => {
|
||||
expectAndFail(data).toMatchObject({
|
||||
input: {
|
||||
commentID: comment.id,
|
||||
commentRevisionID: comment.revision.id,
|
||||
},
|
||||
const acceptCommentStub = createMutationResolverStub<
|
||||
MutationToAcceptCommentResolver
|
||||
>(({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
commentID: comment.id,
|
||||
commentRevisionID: comment.revision.id,
|
||||
});
|
||||
return {
|
||||
comment: {
|
||||
id: comment.id,
|
||||
status: "ACCEPTED",
|
||||
status: GQLCOMMENT_STATUS.ACCEPTED,
|
||||
},
|
||||
moderationQueues: emptyModerationQueues,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
});
|
||||
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
comment: commentStub,
|
||||
},
|
||||
Mutation: {
|
||||
acceptComment: acceptCommentStub,
|
||||
resolvers: {
|
||||
Query: {
|
||||
comment: commentStub,
|
||||
},
|
||||
Mutation: {
|
||||
acceptComment: acceptCommentStub,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -609,29 +638,30 @@ describe("single comment view", () => {
|
||||
});
|
||||
|
||||
it("rejects single comment", async () => {
|
||||
const rejectCommentStub = sinon.stub().callsFake((_, data) => {
|
||||
expectAndFail(data).toMatchObject({
|
||||
input: {
|
||||
commentID: comment.id,
|
||||
commentRevisionID: comment.revision.id,
|
||||
},
|
||||
const rejectCommentStub = createMutationResolverStub<
|
||||
MutationToRejectCommentResolver
|
||||
>(({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
commentID: comment.id,
|
||||
commentRevisionID: comment.revision.id,
|
||||
});
|
||||
return {
|
||||
comment: {
|
||||
id: comment.id,
|
||||
status: "REJECTED",
|
||||
status: GQLCOMMENT_STATUS.REJECTED,
|
||||
},
|
||||
moderationQueues: emptyModerationQueues,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
});
|
||||
|
||||
const testRenderer = await createTestRenderer({
|
||||
Query: {
|
||||
comment: commentStub,
|
||||
},
|
||||
Mutation: {
|
||||
rejectComment: rejectCommentStub,
|
||||
resolvers: {
|
||||
Query: {
|
||||
comment: commentStub,
|
||||
},
|
||||
Mutation: {
|
||||
rejectComment: rejectCommentStub,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { get, merge } from "lodash";
|
||||
import TestRenderer from "react-test-renderer";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { pureMerge } from "talk-common/utils";
|
||||
import {
|
||||
createSinonStub,
|
||||
createMutationResolverStub,
|
||||
createResolversStub,
|
||||
CreateTestRendererParams,
|
||||
findParentWithType,
|
||||
replaceHistoryLocation,
|
||||
waitForElement,
|
||||
@@ -11,7 +12,12 @@ import {
|
||||
within,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import { GQLSTORY_STATUS } from "talk-framework/schema";
|
||||
import {
|
||||
GQLResolver,
|
||||
GQLSTORY_STATUS,
|
||||
MutationToCloseStoryResolver,
|
||||
MutationToOpenStoryResolver,
|
||||
} from "talk-framework/schema";
|
||||
import create from "../create";
|
||||
import {
|
||||
emptyStories,
|
||||
@@ -21,38 +27,43 @@ import {
|
||||
users,
|
||||
} from "../fixtures";
|
||||
|
||||
const viewer = users.admins[0];
|
||||
|
||||
beforeEach(async () => {
|
||||
replaceHistoryLocation("http://localhost/admin/stories");
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
stories: sinon.stub().callsFake((_, data) => {
|
||||
expectAndFail(data.status).toBeFalsy();
|
||||
return storyConnection;
|
||||
}),
|
||||
viewer: sinon.stub().returns(users.admins[0]),
|
||||
...resolver.Query,
|
||||
},
|
||||
};
|
||||
async function createTestRenderer(
|
||||
params: CreateTestRendererParams<GQLResolver> = {}
|
||||
) {
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
...params,
|
||||
resolvers: pureMerge(
|
||||
createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
settings: () => settings,
|
||||
viewer: () => viewer,
|
||||
stories: ({ variables }) => {
|
||||
expectAndFail(variables.status).toBeFalsy();
|
||||
return storyConnection;
|
||||
},
|
||||
},
|
||||
}),
|
||||
params.resolvers
|
||||
),
|
||||
initLocalState: (localRecord, source, environment) => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
if (params.initLocalState) {
|
||||
params.initLocalState(localRecord, source, environment);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const container = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("stories-container")
|
||||
);
|
||||
return { testRenderer, container };
|
||||
};
|
||||
}
|
||||
|
||||
it("renders stories", async () => {
|
||||
const { container } = await createTestRenderer();
|
||||
@@ -61,25 +72,30 @@ it("renders stories", async () => {
|
||||
|
||||
it("renders empty stories", async () => {
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
users: sinon.stub().returns(emptyStories),
|
||||
},
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
users: () => emptyStories,
|
||||
},
|
||||
}),
|
||||
});
|
||||
expect(within(container).toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("filter by status", async () => {
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
stories: createSinonStub(
|
||||
s => s.onFirstCall().returns(storyConnection),
|
||||
s =>
|
||||
s.onSecondCall().callsFake((_, data) => {
|
||||
expectAndFail(data.status).toBe(GQLSTORY_STATUS.CLOSED);
|
||||
return emptyStories;
|
||||
})
|
||||
),
|
||||
},
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
stories: ({ variables, callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
return storyConnection;
|
||||
default:
|
||||
expectAndFail(variables.status).toBe(GQLSTORY_STATUS.CLOSED);
|
||||
return emptyStories;
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const selectField = within(container).getByLabelText("Search by status");
|
||||
@@ -100,38 +116,42 @@ it("filter by status", async () => {
|
||||
|
||||
it("change story status", async () => {
|
||||
const story = stories[1];
|
||||
const openStory = sinon.stub().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input).toMatchObject({
|
||||
id: story.id,
|
||||
});
|
||||
const storyRecord = merge({}, story, {
|
||||
status: GQLSTORY_STATUS.OPEN,
|
||||
createdAt: false,
|
||||
isClosed: false,
|
||||
});
|
||||
return {
|
||||
story: storyRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
});
|
||||
const openStory = createMutationResolverStub<MutationToOpenStoryResolver>(
|
||||
({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
id: story.id,
|
||||
});
|
||||
const storyRecord = pureMerge(story, {
|
||||
status: GQLSTORY_STATUS.OPEN,
|
||||
createdAt: false,
|
||||
isClosed: false,
|
||||
});
|
||||
return {
|
||||
story: storyRecord,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const closeStory = sinon.stub().callsFake((_: any, data: any) => {
|
||||
expectAndFail(data.input).toMatchObject({
|
||||
id: story.id,
|
||||
});
|
||||
const storyRecord = merge({}, story, {
|
||||
status: GQLSTORY_STATUS.CLOSED,
|
||||
createdAt: "2018-11-29T16:01:51.897Z",
|
||||
isClosed: true,
|
||||
});
|
||||
return {
|
||||
story: storyRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
});
|
||||
const closeStory = createMutationResolverStub<MutationToCloseStoryResolver>(
|
||||
({ variables }) => {
|
||||
expectAndFail(variables).toMatchObject({
|
||||
id: story.id,
|
||||
});
|
||||
const storyRecord = pureMerge(story, {
|
||||
status: GQLSTORY_STATUS.CLOSED,
|
||||
createdAt: "2018-11-29T16:01:51.897Z",
|
||||
isClosed: true,
|
||||
});
|
||||
return {
|
||||
story: storyRecord,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const { container } = await createTestRenderer({
|
||||
Mutation: { openStory, closeStory },
|
||||
resolvers: {
|
||||
Mutation: { openStory, closeStory },
|
||||
},
|
||||
});
|
||||
|
||||
const storyRow = within(container).getByText(story.metadata!.title!, {
|
||||
@@ -174,23 +194,33 @@ it("change story status", async () => {
|
||||
|
||||
it("load more", async () => {
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
stories: createSinonStub(
|
||||
s =>
|
||||
s.onFirstCall().returns({
|
||||
edges: [
|
||||
{ node: stories[0], cursor: stories[0].createdAt },
|
||||
{ node: stories[1], cursor: stories[1].createdAt },
|
||||
],
|
||||
pageInfo: { endCursor: stories[1].createdAt, hasNextPage: true },
|
||||
}),
|
||||
s =>
|
||||
s.onSecondCall().returns({
|
||||
edges: [{ node: stories[2], cursor: stories[2].createdAt }],
|
||||
pageInfo: { endCursor: stories[2].createdAt, hasNextPage: false },
|
||||
})
|
||||
),
|
||||
},
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
stories: ({ callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
return {
|
||||
edges: [
|
||||
{ node: stories[0], cursor: stories[0].createdAt },
|
||||
{ node: stories[1], cursor: stories[1].createdAt },
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: stories[1].createdAt,
|
||||
hasNextPage: true,
|
||||
},
|
||||
};
|
||||
default:
|
||||
return {
|
||||
edges: [{ node: stories[2], cursor: stories[2].createdAt }],
|
||||
pageInfo: {
|
||||
endCursor: stories[2].createdAt,
|
||||
hasNextPage: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
const loadMore = within(container).getByText("Load More");
|
||||
TestRenderer.act(() => {
|
||||
@@ -206,16 +236,19 @@ it("load more", async () => {
|
||||
|
||||
it("filter by search", async () => {
|
||||
const { container } = await createTestRenderer({
|
||||
Query: {
|
||||
stories: createSinonStub(
|
||||
s => s.onFirstCall().returns(storyConnection),
|
||||
s =>
|
||||
s.onSecondCall().callsFake((_, data) => {
|
||||
expectAndFail(data.query).toBe("search");
|
||||
return emptyStories;
|
||||
})
|
||||
),
|
||||
},
|
||||
resolvers: createResolversStub<GQLResolver>({
|
||||
Query: {
|
||||
stories: ({ variables, callCount }) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
return storyConnection;
|
||||
default:
|
||||
expectAndFail(variables.query).toBe("search");
|
||||
return emptyStories;
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const searchField = within(container).getByLabelText(
|
||||
|
||||
Reference in New Issue
Block a user