[next] Auth Popup v2 (#2101)

* feat: Implement new Sign In view

* feat: Move forgot + resetPassword to new design

* feat: Implement sign up with new design

* fix: narrow gutter

* test: add unit tests

* test: integration tests

* feat: support show / hide password

* feat: support oauth2 flow

* feat: add views for user completion

* feat: implement oauth2 sign up

* test: fix snapshots

* fix: lint

* fix: get more complete mutation response

* fix: removed array of OIDC integrations

* fix: renamed resolver function

* fix: adapt oidc client implementation

* fix: targetFilter should be stream on signup

* fix: removed unneeded message

* fix: moved password into local profile

* fix: made username optional, removed valid null value

* fix: linting

* fix: respect targetFilter

* feat: support user registration mutations

- Added `setUsername`
- Added `setEmail`
- Added `setPassword`
- Added `permit` to `@auth`
- Added `email` to `User`

* fix: fixed issue with query

* feat: added user password update

* feat: complete sign in mutation

* fix: adapt some rebasing gitches

* test: improve tests

* test: unittest for setting auth token

* fix: failing tests

* test: move most tests from enzyme to react-test-renderer

* fix: remove schema warnings in tests

* test: improve window mock

* test: test different social login configurations

* test: test social logins for sign up

* fix: use htmlFor instead of for

* test: more feature tests

* feat: always go through account completion

* test: feature test account completion

* feat: addtional account completion test

* Update start.ts

* chore: refactor auth token retrieval logic
This commit is contained in:
Kiwi
2018-12-20 22:32:04 +01:00
committed by GitHub
parent 326a10dc5d
commit 065cb4b03a
331 changed files with 12476 additions and 7163 deletions
@@ -1,9 +1,10 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import Community from "./Community";
it("renders correctly", () => {
const wrapper = shallow(<Community />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Community />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -11,6 +11,7 @@ it("renders correctly", () => {
title: <span>title</span>,
children: "child",
};
const wrapper = shallow(<ConfigBox {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<ConfigBox {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,6 +1,6 @@
import { shallow } from "enzyme";
import { noop } from "lodash";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -11,6 +11,7 @@ it("renders correctly", () => {
onSave: noop,
onChange: noop,
};
const wrapper = shallow(<Configure {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Configure {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -21,7 +21,7 @@ const Configure: StatelessComponent<Props> = ({
onChange,
children,
}) => (
<MainLayout data-test="configure-container">
<MainLayout data-testid="configure-container">
<Form onSubmit={onSave}>
{({ handleSubmit, submitting, pristine, form, submitError }) => (
<form autoComplete="off" onSubmit={handleSubmit} id="configure-form">
@@ -39,7 +39,7 @@ const Configure: StatelessComponent<Props> = ({
<HorizontalGutter size="double">
<Localized id="configure-sideBar-saveChanges">
<Button
data-test="configure-sideBar-saveChanges"
data-testid="configure-sideBar-saveChanges"
color="success"
variant="filled"
type="submit"
@@ -52,7 +52,7 @@ const Configure: StatelessComponent<Props> = ({
<CallOut
color="error"
fullWidth
data-test="configure-auth-submitError"
data-testid="configure-auth-submitError"
>
{submitError}
</CallOut>
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof Header> = {
children: "child",
};
const wrapper = shallow(<Header {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Header {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,9 +1,10 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import HorizontalRule from "./HorizontalRule";
it("renders correctly", () => {
const wrapper = shallow(<HorizontalRule />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<HorizontalRule />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof Layout> = {
children: "child",
};
const wrapper = shallow(<Layout {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Layout {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof Main> = {
children: "child",
};
const wrapper = shallow(<Main {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Main {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof Moderation> = {
children: "child",
};
const wrapper = shallow(<Moderation {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Moderation {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -22,6 +22,6 @@
.linkActive {
font-weight: var(--font-weight-bold);
margin-left: 0px;
border-left: calc(0.5 * var(--spacing-unit)) solid var(--palette-brand);
border-left: calc(0.5 * var(--spacing-unit)) solid var(--palette-brand-main);
padding-left: var(--spacing-unit);
}
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -11,6 +11,7 @@ it("renders correctly", () => {
to: "/admin",
children: "child",
};
const wrapper = shallow(<Link {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Link {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof Navigation> = {
children: "child",
};
const wrapper = shallow(<Navigation {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Navigation {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof SideBar> = {
children: "child",
};
const wrapper = shallow(<SideBar {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<SideBar {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -2,12 +2,12 @@
exports[`renders correctly 1`] = `
<MainLayout
data-test="configure-container"
data-testid="configure-container"
>
<ReactFinalForm
onSubmit={[Function]}
>
<Component />
[Function]
</ReactFinalForm>
</MainLayout>
`;
@@ -81,7 +81,9 @@ class ConfigureContainer extends React.Component<Props> {
executeCallbacks.push(() =>
this.props.updateSettings({ settings: nextData })
);
await Promise.all(executeCallbacks.map(cb => cb()));
for (const c of executeCallbacks.map(cb => cb())) {
await c;
}
form.initialize(data);
} catch (error) {
if (error instanceof BadUserInputError) {
@@ -8,7 +8,7 @@ import Header from "../../../components/Header";
import FacebookConfigContainer from "../containers/FacebookConfigContainer";
import GoogleConfigContainer from "../containers/GoogleConfigContainer";
import LocalAuthConfigContainer from "../containers/LocalAuthConfigContainer";
import OIDCConfigListContainer from "../containers/OIDCConfigListContainer";
import OIDCConfigContainer from "../containers/OIDCConfigContainer";
import SSOConfigContainer from "../containers/SSOConfigContainer";
interface Props {
@@ -20,8 +20,8 @@ interface Props {
PropTypesOf<typeof SSOConfigContainer>["auth"] &
PropTypesOf<typeof SSOConfigContainer>["authReadOnly"] &
PropTypesOf<typeof LocalAuthConfigContainer>["auth"] &
PropTypesOf<typeof OIDCConfigListContainer>["auth"] &
PropTypesOf<typeof OIDCConfigListContainer>["authReadOnly"];
PropTypesOf<typeof OIDCConfigContainer>["auth"] &
PropTypesOf<typeof OIDCConfigContainer>["authReadOnly"];
onInitValues: (values: any) => void;
}
@@ -39,7 +39,7 @@ const AuthIntegrationsConfig: StatelessComponent<Props> = ({
auth={auth}
onInitValues={onInitValues}
/>
<OIDCConfigListContainer
<OIDCConfigContainer
disabled={disabled}
auth={auth}
authReadOnly={auth}
@@ -38,7 +38,7 @@ const FacebookConfig: StatelessComponent<Props> = ({
callbackURL,
}) => (
<ConfigBoxWithToggleField
data-test="configure-auth-facebook-container"
data-testid="configure-auth-facebook-container"
title={
<Localized id="configure-auth-facebook-loginWith">
<span>Login with Facebook</span>
@@ -1,4 +0,0 @@
.redirectDescriptionIcon {
color: var(--palette-text-secondary);
flex-shrink: 0;
}
@@ -14,7 +14,6 @@ import {
Flex,
FormField,
HorizontalGutter,
Icon,
InputLabel,
TextField,
TextLink,
@@ -31,10 +30,7 @@ import RegistrationField from "./RegistrationField";
import TargetFilterField from "./TargetFilterField";
import ValidationMessage from "./ValidationMessage";
import styles from "./OIDCConfig.css";
interface Props {
index: number;
disabled?: boolean;
callbackURL: string;
disableForDiscover?: boolean;
@@ -48,7 +44,6 @@ const OIDCLink = () => (
const OIDCConfig: StatelessComponent<Props> = ({
disabled,
callbackURL,
index,
onDiscover,
disableForDiscover,
}) => {
@@ -56,20 +51,20 @@ const OIDCConfig: StatelessComponent<Props> = ({
v,
values
) => {
if (values.auth.integrations.oidc[0].enabled) {
if (values.auth.integrations.oidc.enabled) {
return validator(v, values);
}
return "";
};
return (
<ConfigBoxWithToggleField
data-test={`configure-auth-oidc-container-${index}`}
data-testid={`configure-auth-oidc-container`}
title={
<Localized id="configure-auth-oidc-loginWith">
<span>Login with OIDC</span>
</Localized>
}
name={`auth.integrations.oidc.${index}.enabled`}
name={`auth.integrations.oidc.enabled`}
disabled={disabled}
>
{disabledInside => (
@@ -80,22 +75,7 @@ const OIDCConfig: StatelessComponent<Props> = ({
</Typography>
</Localized>
<HorizontalRule />
<RedirectField
url={callbackURL}
description={
<ConfigDescription container="div">
<Flex itemGutter="half">
<Icon className={styles.redirectDescriptionIcon}>error</Icon>
<Localized id="configure-auth-oidc-redirectDescription">
<div>
For OpenID Connect, your Redirect URI will not appear
until you after you save this integration
</div>
</Localized>
</Flex>
</ConfigDescription>
}
/>
<RedirectField url={callbackURL} />
<HorizontalRule />
<FormField>
<Localized id="configure-auth-oidc-providerName">
@@ -109,7 +89,7 @@ const OIDCConfig: StatelessComponent<Props> = ({
</ConfigDescription>
</Localized>
<Field
name={`auth.integrations.oidc.${index}.name`}
name={`auth.integrations.oidc.name`}
validate={validateWhenEnabled(required)}
parse={identity}
>
@@ -137,12 +117,12 @@ const OIDCConfig: StatelessComponent<Props> = ({
</FormField>
<ClientIDField
validate={validateWhenEnabled(required)}
name={`auth.integrations.oidc.${index}.clientID`}
name={`auth.integrations.oidc.clientID`}
disabled={disabledInside}
/>
<ClientSecretField
validate={validateWhenEnabled(required)}
name={`auth.integrations.oidc.${index}.clientSecret`}
name={`auth.integrations.oidc.clientSecret`}
disabled={disabledInside}
/>
<FormField>
@@ -157,7 +137,7 @@ const OIDCConfig: StatelessComponent<Props> = ({
</ConfigDescription>
</Localized>
<Field
name={`auth.integrations.oidc.${index}.issuer`}
name={`auth.integrations.oidc.issuer`}
validate={validateWhenEnabled(
composeValidators(required, validateURL)
)}
@@ -177,7 +157,7 @@ const OIDCConfig: StatelessComponent<Props> = ({
spellCheck={false}
/>
<Button
id="configure-auth-oidc-discover-0"
id="configure-auth-oidc-discover"
variant="filled"
color="primary"
size="small"
@@ -202,7 +182,7 @@ const OIDCConfig: StatelessComponent<Props> = ({
<InputLabel>authorizationURL</InputLabel>
</Localized>
<Field
name={`auth.integrations.oidc.${index}.authorizationURL`}
name={`auth.integrations.oidc.authorizationURL`}
validate={validateWhenEnabled(
composeValidators(required, validateURL)
)}
@@ -235,7 +215,7 @@ const OIDCConfig: StatelessComponent<Props> = ({
<InputLabel>tokenURL</InputLabel>
</Localized>
<Field
name={`auth.integrations.oidc.${index}.tokenURL`}
name={`auth.integrations.oidc.tokenURL`}
validate={validateWhenEnabled(
composeValidators(required, validateURL)
)}
@@ -268,7 +248,7 @@ const OIDCConfig: StatelessComponent<Props> = ({
<InputLabel>jwksURI</InputLabel>
</Localized>
<Field
name={`auth.integrations.oidc.${index}.jwksURI`}
name={`auth.integrations.oidc.jwksURI`}
validate={validateWhenEnabled(
composeValidators(required, validateURL)
)}
@@ -302,11 +282,11 @@ const OIDCConfig: StatelessComponent<Props> = ({
<span>Use OIDC login on</span>
</Localized>
}
name={`auth.integrations.oidc.${index}.targetFilter`}
name={`auth.integrations.oidc.targetFilter`}
disabled={disabledInside}
/>
<RegistrationField
name={`auth.integrations.oidc.${index}.allowRegistration`}
name={`auth.integrations.oidc.allowRegistration`}
disabled={disabledInside}
/>
</HorizontalGutter>
@@ -26,7 +26,7 @@ const SSOKeyField: StatelessComponent<Props> = ({
disabled,
onRegenerate,
}) => (
<FormField data-test="configure-auth-sso-key">
<FormField data-testid="configure-auth-sso-key">
<Localized id="configure-auth-sso-key">
<InputLabel>Key</InputLabel>
</Localized>
@@ -49,7 +49,7 @@ export default class AuthContainer extends React.Component<Props> {
get(data, "auth.integrations.facebook"),
get(data, "auth.integrations.sso"),
get(data, "auth.integrations.local"),
...(get(data, "auth.integrations.oidc") || []),
get(data, "auth.integrations.oidc"),
];
if (!integrations.some((i: any) => i.enabled && i.targetFilter.admin)) {
cancel({
@@ -111,8 +111,8 @@ AuthContainer.routeConfig = {
...SSOConfigContainer_authReadOnly
...LocalAuthConfigContainer_auth
...DisplayNamesConfigContainer_auth
...OIDCConfigListContainer_auth
...OIDCConfigListContainer_authReadOnly
...OIDCConfigContainer_auth
...OIDCConfigContainer_authReadOnly
}
}
}
@@ -1,17 +1,22 @@
import { FormApi } from "final-form";
import PropTypes from "prop-types";
import React from "react";
import { graphql } from "react-relay";
import { OIDCConfigContainer_auth as AuthData } from "talk-admin/__generated__/OIDCConfigContainer_auth.graphql";
import { OIDCConfigContainer_authReadOnly as AuthReadOnlyData } from "talk-admin/__generated__/OIDCConfigContainer_authReadOnly.graphql";
import {
DiscoverOIDCConfigurationFetch,
withDiscoverOIDCConfigurationFetch,
} from "talk-admin/fetches";
import { withFragmentContainer } from "talk-framework/lib/relay";
import OIDCConfig from "../components/OIDCConfig";
interface Props {
index: number;
callbackURL: string;
auth: AuthData;
authReadOnly: AuthReadOnlyData;
onInitValues: (values: AuthData) => void;
disabled?: boolean;
discoverOIDCConfiguration: DiscoverOIDCConfigurationFetch;
}
@@ -34,15 +39,15 @@ class OIDCConfigContainer extends React.Component<Props, State> {
this.setState({ awaitingResponse: true });
try {
const config = await this.props.discoverOIDCConfiguration({
issuer: form.getState().values.auth.integrations.oidc[0].issuer,
issuer: form.getState().values.auth.integrations.oidc.issuer,
});
if (config) {
form.change(
"auth.integrations.oidc.0.authorizationURL",
"auth.integrations.oidc.authorizationURL",
config.authorizationURL
);
form.change("auth.integrations.oidc.0.jwksURI", config.jwksURI);
form.change("auth.integrations.oidc.0.tokenURL", config.tokenURL);
form.change("auth.integrations.oidc.jwksURI", config.jwksURI);
form.change("auth.integrations.oidc.tokenURL", config.tokenURL);
}
} catch (error) {
// tslint:disable-next-line:no-console
@@ -51,13 +56,17 @@ class OIDCConfigContainer extends React.Component<Props, State> {
this.setState({ awaitingResponse: false });
};
constructor(props: Props) {
super(props);
props.onInitValues(props.auth);
}
public render() {
const { disabled, index, callbackURL } = this.props;
const { disabled, authReadOnly } = this.props;
return (
<OIDCConfig
disabled={disabled}
index={index}
callbackURL={callbackURL}
callbackURL={authReadOnly.integrations.oidc.callbackURL}
onDiscover={this.handleDiscover}
disableForDiscover={this.state.awaitingResponse}
/>
@@ -65,6 +74,39 @@ class OIDCConfigContainer extends React.Component<Props, State> {
}
}
const enhanced = withDiscoverOIDCConfigurationFetch(OIDCConfigContainer);
const enhanced = withDiscoverOIDCConfigurationFetch(
withFragmentContainer<Props>({
auth: graphql`
fragment OIDCConfigContainer_auth on Auth {
integrations {
oidc {
enabled
allowRegistration
targetFilter {
admin
stream
}
name
clientID
clientSecret
authorizationURL
tokenURL
jwksURI
issuer
}
}
}
`,
authReadOnly: graphql`
fragment OIDCConfigContainer_authReadOnly on Auth {
integrations {
oidc {
callbackURL
}
}
}
`,
})(OIDCConfigContainer)
);
export default enhanced;
@@ -1,154 +0,0 @@
import { cloneDeep } from "lodash";
import React from "react";
import { graphql } from "react-relay";
import { OIDCConfigListContainer_auth as AuthData } from "talk-admin/__generated__/OIDCConfigListContainer_auth.graphql";
import { OIDCConfigListContainer_authReadOnly as AuthReadOnlyData } from "talk-admin/__generated__/OIDCConfigListContainer_authReadOnly.graphql";
import {
CreateOIDCAuthIntegrationMutation,
UpdateOIDCAuthIntegrationMutation,
withCreateOIDCAuthIntegrationMutation,
withUpdateOIDCAuthIntegrationMutation,
} from "talk-admin/mutations";
import { withFragmentContainer } from "talk-framework/lib/relay";
import {
AddSubmitHook,
RemoveSubmitHook,
SubmitHook,
withSubmitHookContext,
} from "../../../submitHook";
import OIDCConfigContainer from "./OIDCConfigContainer";
interface Props {
auth: AuthData;
authReadOnly: AuthReadOnlyData;
disabled?: boolean;
addSubmitHook: AddSubmitHook;
onInitValues: (values: AuthData) => void;
createOIDCAuthIntegration: CreateOIDCAuthIntegrationMutation;
updateOIDCAuthIntegration: UpdateOIDCAuthIntegrationMutation;
}
class OIDCConfigListContainer extends React.Component<Props> {
private removeSubmitHook: RemoveSubmitHook;
constructor(props: Props) {
super(props);
props.onInitValues(this.getAuthWithDefault());
this.removeSubmitHook = this.props.addSubmitHook(this.submitHook);
}
public componentWillUnmount() {
this.removeSubmitHook();
}
private submitHook: SubmitHook = async (data: any, { onExecute }) => {
const cloned = cloneDeep(data);
const oidc = cloned.auth.integrations.oidc;
delete cloned.auth.integrations.oidc;
if (this.props.auth.integrations.oidc.length === 0) {
if (oidc[0].enabled) {
onExecute(() =>
this.props.createOIDCAuthIntegration({ configuration: oidc[0] })
);
}
} else {
onExecute(() =>
this.props.updateOIDCAuthIntegration({
configuration: oidc[0],
id: this.props.authReadOnly.integrations.oidc[0].id,
})
);
}
return cloned;
};
private getAuthWithDefault(): AuthData {
return this.props.auth.integrations.oidc.length === 0
? ({
integrations: {
oidc: [
{
clientID: "",
clientSecret: "",
allowRegistration: false,
targetFilter: {
admin: true,
stream: true,
},
name: "",
authorizationURL: "",
tokenURL: "",
jwksURI: "",
issuer: "",
},
],
},
} as any)
: this.props.auth;
}
public render() {
const { disabled, authReadOnly } = this.props;
const integrations = this.getAuthWithDefault().integrations.oidc.map(
(data, i) => (
<OIDCConfigContainer
key={i}
disabled={disabled}
index={i}
callbackURL={
(authReadOnly.integrations.oidc[i] &&
authReadOnly.integrations.oidc[i].callbackURL) ||
""
}
/>
)
);
return <>{integrations}</>;
}
}
const enhanced = withFragmentContainer<Props>({
auth: graphql`
fragment OIDCConfigListContainer_auth on Auth {
integrations {
oidc {
enabled
allowRegistration
targetFilter {
admin
stream
}
name
clientID
clientSecret
authorizationURL
tokenURL
jwksURI
issuer
}
}
}
`,
authReadOnly: graphql`
fragment OIDCConfigListContainer_authReadOnly on Auth {
integrations {
oidc {
id
callbackURL
}
}
}
`,
})(
withCreateOIDCAuthIntegrationMutation(
withUpdateOIDCAuthIntegrationMutation(
withSubmitHookContext(addSubmitHook => ({ addSubmitHook }))(
OIDCConfigListContainer
)
)
)
);
export default enhanced;
@@ -1,9 +1,10 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import Login from "./Login";
it("renders correctly", () => {
const wrapper = shallow(<Login />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Login />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -4,12 +4,12 @@ import { Field, Form } from "react-final-form";
import { OnSubmit } from "talk-framework/lib/form";
import { PasswordField } from "talk-framework/components";
import {
composeValidators,
required,
validateEmail,
} from "talk-framework/lib/validation";
import {
Button,
CallOut,
@@ -87,12 +87,11 @@ const SignIn: StatelessComponent<Props> = props => (
id="login-signIn-passwordTextField"
attrs={{ placeholder: true }}
>
<TextField
<PasswordField
name={input.name}
onChange={input.onChange}
value={input.value}
placeholder="Password"
type="password"
color={
meta.touched && (meta.error || meta.submitError)
? "error"
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import AcceptButton from "./AcceptButton";
@@ -9,14 +9,16 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof AcceptButton> = {
invert: false,
};
const wrapper = shallow(<AcceptButton {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<AcceptButton {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders correctly inverted", () => {
const props: PropTypesOf<typeof AcceptButton> = {
invert: true,
};
const wrapper = shallow(<AcceptButton {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<AcceptButton {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import CommentContent from "./CommentContent";
@@ -12,8 +12,9 @@ it("renders correctly", () => {
className: "custom",
children: "Hello <strong>idiot</strong>, you fucking bastard",
};
const wrapper = shallow(<CommentContent {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<CommentContent {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders empty words correctly", () => {
@@ -23,6 +24,7 @@ it("renders empty words correctly", () => {
className: "custom",
children: "Hello <strong>idiot</strong>, you fucking bastard",
};
const wrapper = shallow(<CommentContent {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<CommentContent {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof InReplyTo> = {
children: "Username",
};
const wrapper = shallow(<InReplyTo {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<InReplyTo {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -3,7 +3,7 @@ import React, { StatelessComponent } from "react";
import { Flex, Spinner } from "talk-ui/components";
const LoadingQueue: StatelessComponent = () => (
<Flex justifyContent="center" data-test="loading-moderate-container">
<Flex justifyContent="center" data-testid="loading-moderate-container">
<Spinner />
</Flex>
);
@@ -1,12 +1,13 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import Moderate from "./Moderate";
import { PropTypesOf } from "talk-framework/types";
it("renders correctly", () => {
const wrapper = shallow(<Moderate />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Moderate />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders correctly with counts", () => {
@@ -15,6 +16,7 @@ it("renders correctly with counts", () => {
reportedCount: 4,
pendingCount: 0,
};
const wrapper = shallow(<Moderate {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Moderate {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -20,8 +20,8 @@ const Moderate: StatelessComponent<Props> = ({
pendingCount,
children,
}) => (
<div data-test="moderate-container">
<SubBar data-test="moderate-subBar-container">
<div data-testid="moderate-container">
<SubBar data-testid="moderate-subBar-container">
<Navigation
unmoderatedCount={unmoderatedCount}
reportedCount={reportedCount}
@@ -29,7 +29,7 @@ const Moderate: StatelessComponent<Props> = ({
/>
</SubBar>
<div className={styles.background} />
<MainLayout data-test="moderate-main-container">
<MainLayout data-testid="moderate-main-container">
<main className={styles.main}>{children}</main>
</MainLayout>
</div>
@@ -1,6 +1,6 @@
import { shallow } from "enzyme";
import { noop } from "lodash";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { removeFragmentRefs } from "talk-framework/testHelpers";
import { PropTypesOf } from "talk-framework/types";
@@ -28,8 +28,9 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof ModerateCardN> = {
...baseProps,
};
const wrapper = shallow(<ModerateCardN {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<ModerateCardN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders reply correctly", () => {
@@ -37,8 +38,9 @@ it("renders reply correctly", () => {
...baseProps,
inReplyTo: "Julian",
};
const wrapper = shallow(<ModerateCardN {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<ModerateCardN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders accepted correctly", () => {
@@ -46,8 +48,9 @@ it("renders accepted correctly", () => {
...baseProps,
status: "accepted",
};
const wrapper = shallow(<ModerateCardN {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<ModerateCardN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders rejected correctly", () => {
@@ -55,8 +58,9 @@ it("renders rejected correctly", () => {
...baseProps,
status: "rejected",
};
const wrapper = shallow(<ModerateCardN {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<ModerateCardN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders dangling correctly", () => {
@@ -64,6 +68,7 @@ it("renders dangling correctly", () => {
...baseProps,
dangling: true,
};
const wrapper = shallow(<ModerateCardN {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<ModerateCardN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -53,7 +53,7 @@ const ModerateCard: StatelessComponent<Props> = ({
}) => (
<Card
className={cn(styles.root, { [styles.dangling]: dangling })}
data-test={`moderate-comment-${id}`}
data-testid={`moderate-comment-${id}`}
>
<Flex>
<div className={styles.mainContainer}>
@@ -1,12 +1,13 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import Navigation from "./Navigation";
import { PropTypesOf } from "talk-framework/types";
it("renders correctly", () => {
const wrapper = shallow(<Navigation />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Navigation />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders correctly with counts", () => {
@@ -15,6 +16,7 @@ it("renders correctly with counts", () => {
reportedCount: 4,
pendingCount: 0,
};
const wrapper = shallow(<Navigation {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Navigation {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -24,7 +24,7 @@ const Navigation: StatelessComponent<Props> = ({
<span>Reported</span>
</Localized>
{reportedCount !== undefined && (
<Counter data-test="moderate-navigation-reported-count">
<Counter data-testid="moderate-navigation-reported-count">
{reportedCount}
</Counter>
)}
@@ -35,7 +35,7 @@ const Navigation: StatelessComponent<Props> = ({
<span>Pending</span>
</Localized>
{pendingCount !== undefined && (
<Counter data-test="moderate-navigation-pending-count">
<Counter data-testid="moderate-navigation-pending-count">
{pendingCount}
</Counter>
)}
@@ -46,7 +46,7 @@ const Navigation: StatelessComponent<Props> = ({
<span>Unmoderated</span>
</Localized>
{unmoderatedCount !== undefined && (
<Counter data-test="moderate-navigation-unmoderated-count">
<Counter data-testid="moderate-navigation-unmoderated-count">
{unmoderatedCount}
</Counter>
)}
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -10,6 +10,7 @@ it("renders correctly", () => {
to: "/moderate",
children: "link",
};
const wrapper = shallow(<NavigationLink {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<NavigationLink {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,6 +1,6 @@
import { shallow } from "enzyme";
import { noop } from "lodash";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { removeFragmentRefs } from "talk-framework/testHelpers";
import { PropTypesOf } from "talk-framework/types";
@@ -18,8 +18,9 @@ it("renders correctly with load more", () => {
disableLoadMore: false,
danglingLogic: () => true,
};
const wrapper = shallow(<QueueN {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<QueueN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders correctly without load more", () => {
@@ -31,6 +32,7 @@ it("renders correctly without load more", () => {
disableLoadMore: false,
danglingLogic: () => true,
};
const wrapper = shallow(<QueueN {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<QueueN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import RejectButton from "./RejectButton";
@@ -9,14 +9,16 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof RejectButton> = {
invert: false,
};
const wrapper = shallow(<RejectButton {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<RejectButton {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders correctly inverted", () => {
const props: PropTypesOf<typeof RejectButton> = {
invert: true,
};
const wrapper = shallow(<RejectButton {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<RejectButton {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof SingleModerate> = {
children: "singe comment queue",
};
const wrapper = shallow(<SingleModerate {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<SingleModerate {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -12,7 +12,7 @@ interface Props {
}
const Moderate: StatelessComponent<Props> = ({ children }) => (
<div data-test="single-moderate-container">
<div data-testid="single-moderate-container">
<SubBar className={styles.subBar} gutterBegin gutterEnd>
<Localized id="moderate-single-goToModerationQueues">
<Link className={styles.subBarBegin} to="/admin/moderate/">
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "talk-framework/types";
@@ -9,6 +9,7 @@ it("renders correctly", () => {
const props: PropTypesOf<typeof Timestamp> = {
children: "1995-12-17T03:24:00.000Z",
};
const wrapper = shallow(<Timestamp {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Timestamp {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -2,10 +2,10 @@
exports[`renders correctly 1`] = `
<div
data-test="moderate-container"
data-testid="moderate-container"
>
<withPropsOnChange(SubBar)
data-test="moderate-subBar-container"
data-testid="moderate-subBar-container"
>
<Navigation />
</withPropsOnChange(SubBar)>
@@ -13,7 +13,7 @@ exports[`renders correctly 1`] = `
className="Moderate-background"
/>
<MainLayout
data-test="moderate-main-container"
data-testid="moderate-main-container"
>
<main
className="Moderate-main"
@@ -24,10 +24,10 @@ exports[`renders correctly 1`] = `
exports[`renders correctly with counts 1`] = `
<div
data-test="moderate-container"
data-testid="moderate-container"
>
<withPropsOnChange(SubBar)
data-test="moderate-subBar-container"
data-testid="moderate-subBar-container"
>
<Navigation
pendingCount={0}
@@ -39,7 +39,7 @@ exports[`renders correctly with counts 1`] = `
className="Moderate-background"
/>
<MainLayout
data-test="moderate-main-container"
data-testid="moderate-main-container"
>
<main
className="Moderate-main"
@@ -3,7 +3,7 @@
exports[`renders accepted correctly 1`] = `
<withPropsOnChange(Card)
className="ModerateCard-root"
data-test="moderate-comment-comment-id"
data-testid="moderate-comment-comment-id"
>
<withPropsOnChange(Flex)>
<div
@@ -112,7 +112,7 @@ exports[`renders accepted correctly 1`] = `
exports[`renders correctly 1`] = `
<withPropsOnChange(Card)
className="ModerateCard-root"
data-test="moderate-comment-comment-id"
data-testid="moderate-comment-comment-id"
>
<withPropsOnChange(Flex)>
<div
@@ -220,7 +220,7 @@ exports[`renders correctly 1`] = `
exports[`renders dangling correctly 1`] = `
<withPropsOnChange(Card)
className="ModerateCard-root ModerateCard-dangling"
data-test="moderate-comment-comment-id"
data-testid="moderate-comment-comment-id"
>
<withPropsOnChange(Flex)>
<div
@@ -330,7 +330,7 @@ exports[`renders dangling correctly 1`] = `
exports[`renders rejected correctly 1`] = `
<withPropsOnChange(Card)
className="ModerateCard-root"
data-test="moderate-comment-comment-id"
data-testid="moderate-comment-comment-id"
>
<withPropsOnChange(Flex)>
<div
@@ -439,7 +439,7 @@ exports[`renders rejected correctly 1`] = `
exports[`renders reply correctly 1`] = `
<withPropsOnChange(Card)
className="ModerateCard-root"
data-test="moderate-comment-comment-id"
data-testid="moderate-comment-comment-id"
>
<withPropsOnChange(Flex)>
<div
@@ -77,7 +77,7 @@ exports[`renders correctly with counts 1`] = `
</span>
</Localized>
<withPropsOnChange(Counter)
data-test="moderate-navigation-reported-count"
data-testid="moderate-navigation-reported-count"
>
4
</withPropsOnChange(Counter)>
@@ -96,7 +96,7 @@ exports[`renders correctly with counts 1`] = `
</span>
</Localized>
<withPropsOnChange(Counter)
data-test="moderate-navigation-pending-count"
data-testid="moderate-navigation-pending-count"
>
0
</withPropsOnChange(Counter)>
@@ -115,7 +115,7 @@ exports[`renders correctly with counts 1`] = `
</span>
</Localized>
<withPropsOnChange(Counter)
data-test="moderate-navigation-unmoderated-count"
data-testid="moderate-navigation-unmoderated-count"
>
3
</withPropsOnChange(Counter)>
@@ -2,7 +2,7 @@
exports[`renders correctly 1`] = `
<div
data-test="single-moderate-container"
data-testid="single-moderate-container"
>
<withPropsOnChange(SubBar)
className="SingleModerate-subBar"
@@ -1,5 +1,5 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { removeFragmentRefs } from "talk-framework/testHelpers";
import { PropTypesOf } from "talk-framework/types";
@@ -28,8 +28,9 @@ it("renders all markers", () => {
},
},
};
const wrapper = shallow(<MarkersContainerN {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<MarkersContainerN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders some markers", () => {
@@ -52,6 +53,7 @@ it("renders some markers", () => {
},
},
};
const wrapper = shallow(<MarkersContainerN {...props} />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<MarkersContainerN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -4,7 +4,6 @@ exports[`renders all markers 1`] = `
Array [
<Localized
id="moderate-marker-preMod"
key="0"
>
<withPropsOnChange(Marker)
color="primary"
@@ -14,7 +13,6 @@ Array [
</Localized>,
<Localized
id="moderate-marker-link"
key="1"
>
<withPropsOnChange(Marker)
color="primary"
@@ -24,7 +22,6 @@ Array [
</Localized>,
<Localized
id="moderate-marker-bannedWord"
key="2"
>
<withPropsOnChange(Marker)
color="error"
@@ -34,7 +31,6 @@ Array [
</Localized>,
<Localized
id="moderate-marker-suspectWord"
key="3"
>
<withPropsOnChange(Marker)
color="error"
@@ -45,7 +41,6 @@ Array [
</Localized>,
<Localized
id="moderate-marker-spam"
key="4"
>
<withPropsOnChange(Marker)
color="error"
@@ -55,7 +50,6 @@ Array [
</Localized>,
<Localized
id="moderate-marker-toxic"
key="5"
>
<withPropsOnChange(Marker)
color="error"
@@ -65,7 +59,6 @@ Array [
</Localized>,
<Localized
id="moderate-marker-karma"
key="6"
>
<withPropsOnChange(Marker)
color="error"
@@ -75,7 +68,6 @@ Array [
</Localized>,
<withPropsOnChange(Marker)
color="error"
key="7"
>
<Localized
id="moderate-marker-offensive"
@@ -91,7 +83,6 @@ Array [
</withPropsOnChange(Marker)>,
<withPropsOnChange(Marker)
color="error"
key="8"
>
<Localized
id="moderate-marker-spam"
@@ -112,7 +103,6 @@ exports[`renders some markers 1`] = `
Array [
<Localized
id="moderate-marker-preMod"
key="9"
>
<withPropsOnChange(Marker)
color="primary"
@@ -120,10 +110,9 @@ Array [
Pre-Mod
</withPropsOnChange(Marker)>
</Localized>,
"",
null,
<Localized
id="moderate-marker-bannedWord"
key="10"
>
<withPropsOnChange(Marker)
color="error"
@@ -131,11 +120,10 @@ Array [
Banned Word
</withPropsOnChange(Marker)>
</Localized>,
"",
"",
null,
null,
<Localized
id="moderate-marker-toxic"
key="11"
>
<withPropsOnChange(Marker)
color="error"
@@ -145,7 +133,6 @@ Array [
</Localized>,
<Localized
id="moderate-marker-karma"
key="12"
>
<withPropsOnChange(Marker)
color="error"
@@ -155,7 +142,6 @@ Array [
</Localized>,
<withPropsOnChange(Marker)
color="error"
key="13"
>
<Localized
id="moderate-marker-offensive"
@@ -169,6 +155,6 @@ Array [
2
</withPropsOnChange(Count)>
</withPropsOnChange(Marker)>,
"",
null,
]
`;
@@ -1,9 +1,10 @@
import { shallow } from "enzyme";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import Stories from "./Stories";
it("renders correctly", () => {
const wrapper = shallow(<Stories />);
expect(wrapper).toMatchSnapshot();
const renderer = createRenderer();
renderer.render(<Stories />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});