mirror of
https://github.com/wassname/talk.git
synced 2026-09-11 12:51:33 +08:00
[next] Implement configuration panes (#2173)
* feat: moderation config * feat: configure banned and suspect words * chore: upgrade react and test libs to the newest version <3 * chore: upgrade typescript + some refactor * feat: general, organization and advanced configuration panes * fix: translation * feat: speedup fetching markdown editor * feat: localize markdown editor * chore: refactor container names * chore: rename infobox to communityGuidelines * feat: closing comment streams duration config * test: add feature tests for configurations * fix: mock only console.error * chore: upgrade node * chore: require node >= 10 * fix: better validation and default values * feat: Make DurationField a general purpose component and reuse for Edit Comment Timeframe * test: add unit test for duration field * fix: patch for bug when built in production * chore: bump npm version to latest * fix: adapted Dockerfile to new version of node * refactor: harmonized seconds/milliseconds to seconds * fix: resolve bug from merge conflict
This commit is contained in:
@@ -22,16 +22,20 @@ exports[`accepts valid email 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
@@ -42,16 +46,20 @@ exports[`accepts valid email 1`] = `
|
||||
>
|
||||
Confirm Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -104,16 +112,20 @@ exports[`accepts valid email confirmation 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={true}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={true}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
@@ -124,16 +136,20 @@ exports[`accepts valid email confirmation 1`] = `
|
||||
>
|
||||
Confirm Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={true}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={true}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeLarge Button-colorPrimary Button-variantFilled Button-fullWidth Button-disabled"
|
||||
@@ -173,16 +189,20 @@ exports[`checks for invalid email 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="invalid-email"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="invalid-email"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -206,16 +226,20 @@ exports[`checks for invalid email 1`] = `
|
||||
>
|
||||
Confirm Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value="invalid-confirmation-email"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value="invalid-confirmation-email"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -297,16 +321,20 @@ exports[`renders addEmailAddress view 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
@@ -317,16 +345,20 @@ exports[`renders addEmailAddress view 1`] = `
|
||||
>
|
||||
Confirm Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeLarge Button-colorPrimary Button-variantFilled Button-fullWidth"
|
||||
@@ -371,16 +403,20 @@ exports[`shows error when submitting empty form 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -404,16 +440,20 @@ exports[`shows error when submitting empty form 1`] = `
|
||||
>
|
||||
Confirm Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -478,16 +518,20 @@ GraphQL request (4:3)
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
@@ -498,16 +542,20 @@ GraphQL request (4:3)
|
||||
>
|
||||
Confirm Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeLarge Button-colorPrimary Button-variantFilled Button-fullWidth"
|
||||
@@ -547,16 +595,20 @@ exports[`successfully sets email 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
@@ -567,16 +619,20 @@ exports[`successfully sets email 1`] = `
|
||||
>
|
||||
Confirm Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="confirmEmail"
|
||||
name="confirmEmail"
|
||||
onChange={[Function]}
|
||||
placeholder="Confirm Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeLarge Button-colorPrimary Button-variantFilled Button-fullWidth"
|
||||
|
||||
@@ -27,16 +27,20 @@ exports[`accepts valid username 1`] = `
|
||||
>
|
||||
You may use “_” and “.” Spaces not permitted.
|
||||
</p>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={true}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value="hans"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={true}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value="hans"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeLarge Button-colorPrimary Button-variantFilled Button-fullWidth Button-disabled"
|
||||
@@ -81,16 +85,20 @@ exports[`checks for invalid username 1`] = `
|
||||
>
|
||||
You may use “_” and “.” Spaces not permitted.
|
||||
</p>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value="x"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value="x"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -177,16 +185,20 @@ exports[`renders createUsername view 1`] = `
|
||||
>
|
||||
You may use “_” and “.” Spaces not permitted.
|
||||
</p>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeLarge Button-colorPrimary Button-variantFilled Button-fullWidth"
|
||||
@@ -236,16 +248,20 @@ exports[`shows error when submitting empty form 1`] = `
|
||||
>
|
||||
You may use “_” and “.” Spaces not permitted.
|
||||
</p>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -315,16 +331,20 @@ GraphQL request (4:3)
|
||||
>
|
||||
You may use “_” and “.” Spaces not permitted.
|
||||
</p>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value="hans"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value="hans"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeLarge Button-colorPrimary Button-variantFilled Button-fullWidth"
|
||||
@@ -369,16 +389,20 @@ exports[`successfully sets username 1`] = `
|
||||
>
|
||||
You may use “_” and “.” Spaces not permitted.
|
||||
</p>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="username"
|
||||
name="username"
|
||||
onChange={[Function]}
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeLarge Button-colorPrimary Button-variantFilled Button-fullWidth"
|
||||
|
||||
@@ -17,16 +17,20 @@ exports[`accepts correct password 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -124,16 +128,20 @@ exports[`accepts valid email 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
@@ -231,16 +239,20 @@ exports[`checks for invalid email 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="invalid-email"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="invalid-email"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -428,16 +440,20 @@ exports[`renders sign in form 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
@@ -530,16 +546,20 @@ exports[`shows error when submitting empty form 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorError TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorError"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="Message-root Message-colorError Message-fullWidth"
|
||||
>
|
||||
@@ -655,16 +675,20 @@ exports[`shows server error 1`] = `
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
className="TextField-root TextField-colorRegular TextField-fullWidth"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="email"
|
||||
name="email"
|
||||
onChange={[Function]}
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value="hans@test.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders configure advanced 1`] = `
|
||||
<div
|
||||
className="MainLayout-root"
|
||||
data-testid="configure-container"
|
||||
>
|
||||
<form
|
||||
autoComplete="off"
|
||||
id="configure-form"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<div
|
||||
className="Flex-root Layout-root Flex-flex"
|
||||
>
|
||||
<div
|
||||
className="SideBar-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<nav
|
||||
className="Navigation-root"
|
||||
>
|
||||
<ul
|
||||
className="Navigation-ul"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/general"
|
||||
onClick={[Function]}
|
||||
>
|
||||
General
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/organization"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Organization
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/moderation"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Moderation
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/wordList"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Banned and Suspect Words
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/auth"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Authentication
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link Link-linkActive"
|
||||
href="/admin/configure/advanced"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Advanced
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeRegular Button-colorSuccess Button-variantFilled Button-disabled"
|
||||
data-testid="configure-sideBar-saveChanges"
|
||||
disabled={true}
|
||||
onBlur={[Function]}
|
||||
onFocus={[Function]}
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
type="submit"
|
||||
>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Main-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
data-testid="configure-advancedContainer"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-full"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
htmlFor="configure-advanced-customCssUrl"
|
||||
>
|
||||
Custom CSS
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.
|
||||
</p>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="configure-advanced-customCssUrl"
|
||||
name="customCssUrl"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-full"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
htmlFor="configure-advanced-domains"
|
||||
>
|
||||
Permitted Domains
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Domains where your Talk instance is allowed to be embedded.
|
||||
Typical use is localhost, staging.yourdomain.com,
|
||||
yourdomain.com, etc.
|
||||
</p>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="configure-advanced-domains"
|
||||
name="domains"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value="localhost:8080"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,604 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders configure general 1`] = `
|
||||
<div
|
||||
className="MainLayout-root"
|
||||
data-testid="configure-container"
|
||||
>
|
||||
<form
|
||||
autoComplete="off"
|
||||
id="configure-form"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<div
|
||||
className="Flex-root Layout-root Flex-flex"
|
||||
>
|
||||
<div
|
||||
className="SideBar-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<nav
|
||||
className="Navigation-root"
|
||||
>
|
||||
<ul
|
||||
className="Navigation-ul"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link Link-linkActive"
|
||||
href="/admin/configure/general"
|
||||
onClick={[Function]}
|
||||
>
|
||||
General
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/organization"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Organization
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/moderation"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Moderation
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/wordList"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Banned and Suspect Words
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/auth"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Authentication
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/advanced"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Advanced
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeRegular Button-colorSuccess Button-variantFilled Button-disabled"
|
||||
data-testid="configure-sideBar-saveChanges"
|
||||
disabled={true}
|
||||
onBlur={[Function]}
|
||||
onFocus={[Function]}
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
type="submit"
|
||||
>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Main-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
data-testid="configure-generalContainer"
|
||||
>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
>
|
||||
Community Guidelines Summary
|
||||
</legend>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
>
|
||||
Show Community Guidelines Summary
|
||||
</legend>
|
||||
<div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="communityGuidelinesEnable-true"
|
||||
name="communityGuidelinesEnable"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={true}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="communityGuidelinesEnable-true"
|
||||
>
|
||||
On
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={true}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="communityGuidelinesEnable-fase"
|
||||
name="communityGuidelinesEnable"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={false}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="communityGuidelinesEnable-fase"
|
||||
>
|
||||
Off
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-general-guidelines-content"
|
||||
>
|
||||
Community Guidelines Summary
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Write a summary of your community guidelines that will appear
|
||||
at the top of each comment stream sitewide. Your summary can be
|
||||
formatted using Markdown Syntax. More information on how to use
|
||||
Markdown can be found
|
||||
<a
|
||||
className="ExternalLink-root"
|
||||
href="#"
|
||||
target="_blank"
|
||||
>
|
||||
here
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className="MarkdownEditor-wrapper"
|
||||
>
|
||||
<textarea
|
||||
id="configure-general-guidelines-content"
|
||||
name="communityGuidelines"
|
||||
onChange={[Function]}
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
>
|
||||
Comment Length
|
||||
</legend>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Set a limit on the length of comments sitewide
|
||||
</p>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
>
|
||||
Limit Comment Length
|
||||
</label>
|
||||
<div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="charCount.enabled-true"
|
||||
name="charCount.enabled"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={true}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="charCount.enabled-true"
|
||||
>
|
||||
On
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={true}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="charCount.enabled-fase"
|
||||
name="charCount.enabled"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={false}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="charCount.enabled-fase"
|
||||
>
|
||||
Off
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-general-commentLength-min"
|
||||
>
|
||||
Minimum Comment Length
|
||||
</label>
|
||||
<div
|
||||
className="TextField-root CommentLengthConfig-commentLengthTextInput"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular TextField-textAlignCenter"
|
||||
disabled={false}
|
||||
id="configure-general-commentLength-min"
|
||||
name="charCount.min"
|
||||
onChange={[Function]}
|
||||
placeholder="No limit"
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value={3}
|
||||
/>
|
||||
<p
|
||||
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
|
||||
>
|
||||
Characters
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-general-commentLength-max"
|
||||
>
|
||||
Maximum Comment Length
|
||||
</label>
|
||||
<div
|
||||
className="TextField-root CommentLengthConfig-commentLengthTextInput"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular TextField-textAlignCenter"
|
||||
disabled={false}
|
||||
id="configure-general-commentLength-max"
|
||||
name="charCount.max"
|
||||
onChange={[Function]}
|
||||
placeholder="No limit"
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value={1000}
|
||||
/>
|
||||
<p
|
||||
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
|
||||
>
|
||||
Characters
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
|
||||
>
|
||||
<h1
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
>
|
||||
Comment Editing
|
||||
</h1>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Set a limit on how long commenters have to edit their comments sitewide.
|
||||
Edited comments are marked as (Edited) on the comment stream and the
|
||||
moderation panel.
|
||||
</p>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
>
|
||||
Comment Edit Timeframe
|
||||
</legend>
|
||||
<div
|
||||
className="Flex-root Flex-flex Flex-itemGutter"
|
||||
>
|
||||
<div
|
||||
className="TextField-root DurationField-value"
|
||||
>
|
||||
<input
|
||||
aria-label="value"
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular TextField-textAlignCenter"
|
||||
disabled={false}
|
||||
name="editCommentWindowLength-value"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value="500"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className="SelectField-root"
|
||||
>
|
||||
<select
|
||||
aria-label="unit"
|
||||
className="SelectField-select DurationField-unit"
|
||||
disabled={false}
|
||||
name="editCommentWindowLength-unit"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
value="60"
|
||||
>
|
||||
<option
|
||||
value="1"
|
||||
>
|
||||
Seconds
|
||||
</option>
|
||||
<option
|
||||
value="60"
|
||||
>
|
||||
Minutes
|
||||
</option>
|
||||
<option
|
||||
value="3600"
|
||||
>
|
||||
Hours
|
||||
</option>
|
||||
</select>
|
||||
<span
|
||||
aria-hidden={true}
|
||||
className="SelectField-iconWrapper"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="Icon-root Icon-sm"
|
||||
>
|
||||
expand_more
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
>
|
||||
Closing Comment Streams
|
||||
</legend>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Set comment streams to close after a defined period of time after a story’s publication
|
||||
</p>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
>
|
||||
Close Comments Automatically
|
||||
</legend>
|
||||
<div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="autoCloseStream-true"
|
||||
name="autoCloseStream"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={true}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="autoCloseStream-true"
|
||||
>
|
||||
On
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={true}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="autoCloseStream-fase"
|
||||
name="autoCloseStream"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={false}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="autoCloseStream-fase"
|
||||
>
|
||||
Off
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
>
|
||||
Close Comments After
|
||||
</legend>
|
||||
<div
|
||||
className="Flex-root Flex-flex Flex-itemGutter"
|
||||
>
|
||||
<div
|
||||
className="TextField-root DurationField-value"
|
||||
>
|
||||
<input
|
||||
aria-label="value"
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular TextField-textAlignCenter"
|
||||
disabled={false}
|
||||
name="closedTimeout-value"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value="1"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className="SelectField-root"
|
||||
>
|
||||
<select
|
||||
aria-label="unit"
|
||||
className="SelectField-select DurationField-unit"
|
||||
disabled={false}
|
||||
name="closedTimeout-unit"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
value="604800"
|
||||
>
|
||||
<option
|
||||
value="3600"
|
||||
>
|
||||
Hour
|
||||
</option>
|
||||
<option
|
||||
value="86400"
|
||||
>
|
||||
Day
|
||||
</option>
|
||||
<option
|
||||
value="604800"
|
||||
>
|
||||
Week
|
||||
</option>
|
||||
</select>
|
||||
<span
|
||||
aria-hidden={true}
|
||||
className="SelectField-iconWrapper"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="Icon-root Icon-sm"
|
||||
>
|
||||
expand_more
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
htmlFor="configure-general-closedStreamMessage-content"
|
||||
>
|
||||
Closed Stream Message
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Write a message to appear after a story is closed for commenting.
|
||||
</p>
|
||||
<div
|
||||
className="MarkdownEditor-wrapper"
|
||||
>
|
||||
<textarea
|
||||
id="configure-general-closedStreamMessage-content"
|
||||
name="closedMessage"
|
||||
onChange={[Function]}
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,536 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders configure moderation 1`] = `
|
||||
<div
|
||||
className="MainLayout-root"
|
||||
data-testid="configure-container"
|
||||
>
|
||||
<form
|
||||
autoComplete="off"
|
||||
id="configure-form"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<div
|
||||
className="Flex-root Layout-root Flex-flex"
|
||||
>
|
||||
<div
|
||||
className="SideBar-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<nav
|
||||
className="Navigation-root"
|
||||
>
|
||||
<ul
|
||||
className="Navigation-ul"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/general"
|
||||
onClick={[Function]}
|
||||
>
|
||||
General
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/organization"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Organization
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link Link-linkActive"
|
||||
href="/admin/configure/moderation"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Moderation
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/wordList"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Banned and Suspect Words
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/auth"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Authentication
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/advanced"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Advanced
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeRegular Button-colorSuccess Button-variantFilled Button-disabled"
|
||||
data-testid="configure-sideBar-saveChanges"
|
||||
disabled={true}
|
||||
onBlur={[Function]}
|
||||
onFocus={[Function]}
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
type="submit"
|
||||
>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Main-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
data-testid="configure-moderationContainer"
|
||||
>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
>
|
||||
Perspective Toxic Comment Filter
|
||||
</legend>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Using the Perspective API, the Toxic Comment filter warns users when comments exceed the predefined toxicity
|
||||
threshold. Comments with a toxicity score above the threshold
|
||||
<strong>
|
||||
will not be published
|
||||
</strong>
|
||||
and are placed in
|
||||
the
|
||||
<strong>
|
||||
Pending Queue for review by a moderator
|
||||
</strong>
|
||||
. If approved by a moderator, the comment will be published.
|
||||
</p>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
>
|
||||
Toxic Comment Filter
|
||||
</legend>
|
||||
<div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="integrations.perspective.enabled-true"
|
||||
name="integrations.perspective.enabled"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={true}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="integrations.perspective.enabled-true"
|
||||
>
|
||||
On
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={true}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="integrations.perspective.enabled-fase"
|
||||
name="integrations.perspective.enabled"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={false}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="integrations.perspective.enabled-fase"
|
||||
>
|
||||
Off
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-moderation-perspective-threshold"
|
||||
>
|
||||
Toxicity Threshold
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextSecondary"
|
||||
>
|
||||
This value can be set a percentage between 0 and 100. This number represents the likelihood that a
|
||||
comment is toxic, according to Perspective API. By default the treshold is set to 80.
|
||||
</p>
|
||||
<div
|
||||
className="TextField-root PerspectiveConfig-thresholdTextField"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular TextField-textAlignCenter"
|
||||
disabled={false}
|
||||
id="configure-moderation-perspective-threshold"
|
||||
name="integrations.perspective.threshold"
|
||||
onChange={[Function]}
|
||||
placeholder="80"
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<p
|
||||
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
|
||||
>
|
||||
%
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
>
|
||||
Allow Google to Store Comment Data
|
||||
</legend>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextSecondary"
|
||||
>
|
||||
Stored comments will be used for future research and community model building purposes to
|
||||
improve the API over time
|
||||
</p>
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="integrations.perspective.doNotStore-allow"
|
||||
name="integrations.perspective.doNotStore"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={false}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="integrations.perspective.doNotStore-allow"
|
||||
>
|
||||
Allow
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="integrations.perspective.doNotStore-dontAllow"
|
||||
name="integrations.perspective.doNotStore"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={true}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="integrations.perspective.doNotStore-dontAllow"
|
||||
>
|
||||
Don't allow
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div>
|
||||
<h1
|
||||
className="Typography-root Typography-heading3 Typography-colorTextPrimary Subheader-root"
|
||||
>
|
||||
Configuration
|
||||
</h1>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
For additional information on how to set up the Perspective Toxic Comment Filter please visit:
|
||||
|
||||
<a
|
||||
className="ExternalLink-root"
|
||||
href="https://github.com/conversationai/perspectiveapi/blob/master/quickstart.md"
|
||||
target="_blank"
|
||||
>
|
||||
https://github.com/conversationai/perspectiveapi/blob/master/quickstart.md
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-moderation-integrations.perspective.key"
|
||||
>
|
||||
API Key
|
||||
</label>
|
||||
<div
|
||||
className="TextField-root"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="configure-moderation-integrations.perspective.key"
|
||||
name="integrations.perspective.key"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-moderation-perspective-customEndpoint"
|
||||
>
|
||||
Custom Endpoint
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextSecondary"
|
||||
>
|
||||
By default the endpoint is set to https://commentanalyzer.googleapis.com/v1alpha1. You may override this here.
|
||||
</p>
|
||||
<div
|
||||
className="TextField-root"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="configure-moderation-perspective-customEndpoint"
|
||||
name="integrations.perspective.endpoint"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
>
|
||||
Akismet Spam Detection Filter
|
||||
</legend>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Submitted comments are passed to the Akismet API for spam detection.
|
||||
If a comment is determined to be spam, it will prompt the user,
|
||||
indicating that the comment might be considered spam.
|
||||
If the user continues after this point with the still spam-like comment,
|
||||
the comment will be marked as containing spam,
|
||||
<strong>
|
||||
will not be published
|
||||
</strong>
|
||||
and
|
||||
are placed in the
|
||||
<strong>
|
||||
Pending Queue for review by a moderator
|
||||
</strong>
|
||||
. If approved by a moderator,
|
||||
the comment will be published.
|
||||
</p>
|
||||
<fieldset
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<legend
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
>
|
||||
Spam Detection Filter
|
||||
</legend>
|
||||
<div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="integrations.akismet.enabled-true"
|
||||
name="integrations.akismet.enabled"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={true}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="integrations.akismet.enabled-true"
|
||||
>
|
||||
On
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
|
||||
>
|
||||
<input
|
||||
checked={true}
|
||||
className="RadioButton-input"
|
||||
disabled={false}
|
||||
id="integrations.akismet.enabled-fase"
|
||||
name="integrations.akismet.enabled"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
type="radio"
|
||||
value={false}
|
||||
/>
|
||||
<label
|
||||
className="RadioButton-label"
|
||||
htmlFor="integrations.akismet.enabled-fase"
|
||||
>
|
||||
Off
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div>
|
||||
<h1
|
||||
className="Typography-root Typography-heading3 Typography-colorTextPrimary Subheader-root"
|
||||
>
|
||||
Configuration
|
||||
</h1>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Note: You must add your active domain(s)
|
||||
in your Akismet account:
|
||||
<a
|
||||
className="ExternalLink-root"
|
||||
href="https://akismet.com/account/"
|
||||
target="_blank"
|
||||
>
|
||||
https://akismet.com/account/
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-moderation-integrations.akismet.key"
|
||||
>
|
||||
API Key
|
||||
</label>
|
||||
<div
|
||||
className="TextField-root"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="configure-moderation-integrations.akismet.key"
|
||||
name="integrations.akismet.key"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-moderation-akismet-site"
|
||||
>
|
||||
Site URL
|
||||
</label>
|
||||
<div
|
||||
className="TextField-root"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="configure-moderation-akismet-site"
|
||||
name="integrations.akismet.site"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,192 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders configure organization 1`] = `
|
||||
<div
|
||||
className="MainLayout-root"
|
||||
data-testid="configure-container"
|
||||
>
|
||||
<form
|
||||
autoComplete="off"
|
||||
id="configure-form"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<div
|
||||
className="Flex-root Layout-root Flex-flex"
|
||||
>
|
||||
<div
|
||||
className="SideBar-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<nav
|
||||
className="Navigation-root"
|
||||
>
|
||||
<ul
|
||||
className="Navigation-ul"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/general"
|
||||
onClick={[Function]}
|
||||
>
|
||||
General
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link Link-linkActive"
|
||||
href="/admin/configure/organization"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Organization
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/moderation"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Moderation
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/wordList"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Banned and Suspect Words
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/auth"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Authentication
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/advanced"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Advanced
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeRegular Button-colorSuccess Button-variantFilled Button-disabled"
|
||||
data-testid="configure-sideBar-saveChanges"
|
||||
disabled={true}
|
||||
onBlur={[Function]}
|
||||
onFocus={[Function]}
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
type="submit"
|
||||
>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Main-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
data-testid="configure-organizationContainer"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-full"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
htmlFor="configure-organization-organizationName"
|
||||
>
|
||||
Organization Name
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Your organization name will appear on emails sent by Talk to your community and organization members.
|
||||
</p>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="configure-organization-organizationName"
|
||||
name="organizationName"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value="Coral"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-full"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
htmlFor="configure-organization-organizationContactEmail"
|
||||
>
|
||||
Organization Email
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
This email address will be used as in emails and across
|
||||
the platform for community members to get in touch with
|
||||
the organization should they have any questions about the
|
||||
status of their accounts or moderation questions.
|
||||
</p>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
>
|
||||
<input
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="TextField-input TextField-colorRegular"
|
||||
disabled={false}
|
||||
id="configure-organization-organizationContactEmail"
|
||||
name="organizationContactEmail"
|
||||
onChange={[Function]}
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value="coral@test.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,229 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders configure wordList 1`] = `
|
||||
<div
|
||||
className="MainLayout-root"
|
||||
data-testid="configure-container"
|
||||
>
|
||||
<form
|
||||
autoComplete="off"
|
||||
id="configure-form"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<div
|
||||
className="Flex-root Layout-root Flex-flex"
|
||||
>
|
||||
<div
|
||||
className="SideBar-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<nav
|
||||
className="Navigation-root"
|
||||
>
|
||||
<ul
|
||||
className="Navigation-ul"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/general"
|
||||
onClick={[Function]}
|
||||
>
|
||||
General
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/organization"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Organization
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/moderation"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Moderation
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link Link-linkActive"
|
||||
href="/admin/configure/wordList"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Banned and Suspect Words
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/auth"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Authentication
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="Link-link"
|
||||
href="/admin/configure/advanced"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Advanced
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
>
|
||||
<button
|
||||
className="BaseButton-root Button-root Button-sizeRegular Button-colorSuccess Button-variantFilled Button-disabled"
|
||||
data-testid="configure-sideBar-saveChanges"
|
||||
disabled={true}
|
||||
onBlur={[Function]}
|
||||
onFocus={[Function]}
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
type="submit"
|
||||
>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Main-root"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-double"
|
||||
data-testid="configure-wordListContainer"
|
||||
>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
|
||||
>
|
||||
<h1
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
>
|
||||
Banned Words and Phrases
|
||||
</h1>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Comments containing a word or phrase in the banned words list are
|
||||
<strong>
|
||||
automatically rejected and are not published
|
||||
</strong>
|
||||
.
|
||||
</p>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-wordlist-banned"
|
||||
>
|
||||
Banned Word List
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextSecondary"
|
||||
>
|
||||
Separate banned words or phrases with a new line. Attempting to copy
|
||||
and paste a comma separated list?
|
||||
<a
|
||||
className="ExternalLink-root"
|
||||
href="#"
|
||||
target="_blank"
|
||||
>
|
||||
Learn how to convert your list
|
||||
to a new line separated list.
|
||||
</a>
|
||||
</p>
|
||||
<div>
|
||||
<textarea
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="BannedWordListConfig-textArea WordListTextArea-textArea"
|
||||
disabled={false}
|
||||
id="configure-wordlist-banned"
|
||||
name="wordList.banned"
|
||||
onChange={[Function]}
|
||||
spellCheck={false}
|
||||
value="fuck"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
|
||||
>
|
||||
<h1
|
||||
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
|
||||
>
|
||||
Suspect Words and Phrases
|
||||
</h1>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Comments containing a word or phrase in the Suspect Words List
|
||||
are
|
||||
<strong>
|
||||
placed into the Reported Queue for moderator review and are
|
||||
published (if comments are not pre-moderated).
|
||||
</strong>
|
||||
</p>
|
||||
<div
|
||||
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
|
||||
>
|
||||
<label
|
||||
className="Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
||||
htmlFor="configure-wordlist-suspect"
|
||||
>
|
||||
Suspect Word List
|
||||
</label>
|
||||
<p
|
||||
className="Typography-root Typography-detail Typography-colorTextSecondary"
|
||||
>
|
||||
Separate suspect words or phrases with a new line. Attempting to copy
|
||||
and paste a comma separated list?
|
||||
<a
|
||||
className="ExternalLink-root"
|
||||
href="#"
|
||||
target="_blank"
|
||||
>
|
||||
Learn how to convert your list
|
||||
to a new line separated list.
|
||||
</a>
|
||||
</p>
|
||||
<div>
|
||||
<textarea
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="SuspectWordListConfig-textArea WordListTextArea-textArea"
|
||||
disabled={false}
|
||||
id="configure-wordlist-suspect"
|
||||
name="wordList.suspect"
|
||||
onChange={[Function]}
|
||||
spellCheck={false}
|
||||
value="idiot
|
||||
stupid"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,211 @@
|
||||
import mockConsole from "jest-mock-console";
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import {
|
||||
createSinonStub,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
within,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import create from "../create";
|
||||
import { settings, users } from "../fixtures";
|
||||
|
||||
beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/advanced");
|
||||
// Test might pass even when it fails with errors in the log due to:
|
||||
// https://github.com/facebook/jest/issues/3917
|
||||
// We check the console to be error free..
|
||||
mockConsole("error");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Check that there are no errors in the console.
|
||||
// tslint:disable-next-line: no-console
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
me: sinon.stub().returns(users[0]),
|
||||
},
|
||||
};
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("configure-container")
|
||||
);
|
||||
const advancedContainer = await waitForElement(() =>
|
||||
within(configureContainer).getByTestID("configure-advancedContainer")
|
||||
);
|
||||
const saveChangesButton = within(configureContainer).getByTestID(
|
||||
"configure-sideBar-saveChanges"
|
||||
);
|
||||
return {
|
||||
testRenderer,
|
||||
configureContainer,
|
||||
advancedContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
|
||||
it("renders configure advanced", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
expect(within(configureContainer).toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("change custom css", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(data.input.settings.customCssUrl).toEqual("./custom.css");
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const {
|
||||
configureContainer,
|
||||
advancedContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const customCSSField = within(advancedContainer).getByLabelText("Custom CSS");
|
||||
|
||||
// Let's change the customCSS field.
|
||||
customCSSField.props.onChange("./custom.css");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(customCSSField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(customCSSField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.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) => {
|
||||
expect(data.input.settings.domains).toEqual([]);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const {
|
||||
configureContainer,
|
||||
advancedContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const permittedDomainsField = within(advancedContainer).getByLabelText(
|
||||
"Permitted Domains"
|
||||
);
|
||||
|
||||
// Let's change the permitted domains.
|
||||
permittedDomainsField.props.onChange("");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(permittedDomainsField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(permittedDomainsField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.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) => {
|
||||
expect(data.input.settings.domains).toEqual([
|
||||
"localhost:8080",
|
||||
"localhost:3000",
|
||||
]);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const {
|
||||
configureContainer,
|
||||
advancedContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const permittedDomainsField = within(advancedContainer).getByLabelText(
|
||||
"Permitted Domains"
|
||||
);
|
||||
|
||||
// Let's change the permitted domains.
|
||||
permittedDomainsField.props.onChange("localhost:8080, localhost:3000");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(permittedDomainsField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(permittedDomainsField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
@@ -0,0 +1,406 @@
|
||||
import mockConsole from "jest-mock-console";
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import {
|
||||
createSinonStub,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
within,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import create from "../create";
|
||||
import { settings, users } from "../fixtures";
|
||||
|
||||
beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/general");
|
||||
// Test might pass even when it fails with errors in the log due to:
|
||||
// https://github.com/facebook/jest/issues/3917
|
||||
// We check the console to be error free..
|
||||
mockConsole("error");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Check that there are no errors in the console.
|
||||
// tslint:disable-next-line: no-console
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
me: sinon.stub().returns(users[0]),
|
||||
},
|
||||
};
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("configure-container")
|
||||
);
|
||||
const generalContainer = await waitForElement(() =>
|
||||
within(configureContainer).getByTestID("configure-generalContainer")
|
||||
);
|
||||
const saveChangesButton = within(configureContainer).getByTestID(
|
||||
"configure-sideBar-saveChanges"
|
||||
);
|
||||
return {
|
||||
testRenderer,
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
|
||||
it("renders configure general", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
expect(within(configureContainer).toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("change community guidlines", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(data.input.settings.communityGuidelines).toEqual(
|
||||
"This is the community guidlines summary"
|
||||
);
|
||||
expect(data.input.settings.communityGuidelinesEnable).toEqual(true);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const guidelinesContainer = within(generalContainer).getAllByText(
|
||||
"Community Guidelines Summary",
|
||||
{ selector: "fieldset" }
|
||||
)[0];
|
||||
|
||||
const onField = within(guidelinesContainer).getByLabelText("On");
|
||||
const contentField = within(guidelinesContainer).getByLabelText(
|
||||
"Community Guidelines Summary"
|
||||
);
|
||||
|
||||
// Let's enable it.
|
||||
onField.props.onChange(onField.props.value.toString());
|
||||
|
||||
// Let's change the content.
|
||||
contentField.props.onChange("This is the community guidlines summary");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(onField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(onField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change closed stream message", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(data.input.settings.closedMessage).toEqual(
|
||||
"The stream has been closed"
|
||||
);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const contentField = within(generalContainer).getByLabelText(
|
||||
"Closed Stream Message"
|
||||
);
|
||||
|
||||
// Let's change the content.
|
||||
contentField.props.onChange("The stream has been closed");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("change comment editing time", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(data.input.settings.editCommentWindowLength).toEqual(108000);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const durationFieldset = within(generalContainer).getByText(
|
||||
"Comment Edit Timeframe",
|
||||
{ selector: "fieldset" }
|
||||
);
|
||||
const valueField = within(durationFieldset).getByLabelText("value");
|
||||
const unitField = within(durationFieldset).getByLabelText("unit");
|
||||
const hoursOption = within(unitField).getByText(/Hours?/);
|
||||
|
||||
// Let's turn on and set some invalid values.
|
||||
valueField.props.onChange({ target: { value: "" } });
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
expect(
|
||||
within(generalContainer).queryAllByText("This field is required.").length
|
||||
).toBe(1);
|
||||
|
||||
// Let's change to sth valid.
|
||||
valueField.props.onChange({ target: { value: "30" } });
|
||||
unitField.props.onChange({
|
||||
target: { value: hoursOption.props.value.toString() },
|
||||
});
|
||||
|
||||
expect(
|
||||
within(generalContainer).queryAllByText(
|
||||
"Please enter a whole number greater than or equal to 0"
|
||||
).length
|
||||
).toBe(0);
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("change comment length limitations", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(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 {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const commentLengthContainer = within(generalContainer).getByText(
|
||||
"Comment Length",
|
||||
{ selector: "fieldset" }
|
||||
);
|
||||
const onField = within(commentLengthContainer).getByLabelText("On");
|
||||
const minField = within(commentLengthContainer).getByLabelText(
|
||||
"Minimum Comment Length"
|
||||
);
|
||||
const maxField = within(commentLengthContainer).getByLabelText(
|
||||
"Maximum Comment Length"
|
||||
);
|
||||
|
||||
// Let's turn on and set some invalid values.
|
||||
onField.props.onChange(onField.props.value.toString());
|
||||
minField.props.onChange("invalid");
|
||||
maxField.props.onChange("-1");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
expect(
|
||||
within(generalContainer).queryAllByText(
|
||||
"Please enter a whole number greater than 0"
|
||||
).length
|
||||
).toBe(2);
|
||||
|
||||
// Make max smaller than min.
|
||||
minField.props.onChange("1000");
|
||||
maxField.props.onChange("500");
|
||||
|
||||
expect(
|
||||
within(generalContainer).queryAllByText(
|
||||
"Please enter a number longer than the minimum length"
|
||||
).length
|
||||
).toBe(1);
|
||||
|
||||
// Let's change to sth valid.
|
||||
minField.props.onChange("");
|
||||
maxField.props.onChange("3000");
|
||||
|
||||
expect(
|
||||
within(generalContainer).queryAllByText(
|
||||
"Please enter a valid whole number >= 0"
|
||||
).length
|
||||
).toBe(0);
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(minField.props.disabled).toBe(true);
|
||||
expect(maxField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(minField.props.disabled).toBe(false);
|
||||
expect(maxField.props.disabled).toBe(false);
|
||||
});
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change closing comment streams", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(data.input.settings.autoCloseStream).toEqual(true);
|
||||
expect(data.input.settings.closedTimeout).toEqual(2592000);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const {
|
||||
configureContainer,
|
||||
generalContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const closingCommentStreamsContainer = within(generalContainer).getByText(
|
||||
"Closing Comment Streams",
|
||||
{ selector: "fieldset" }
|
||||
);
|
||||
const onField = within(closingCommentStreamsContainer).getByLabelText("On");
|
||||
const durationFieldset = within(closingCommentStreamsContainer).getByText(
|
||||
"Close Comments After",
|
||||
{ selector: "fieldset" }
|
||||
);
|
||||
const valueField = within(durationFieldset).getByLabelText("value");
|
||||
const unitField = within(durationFieldset).getByLabelText("unit");
|
||||
const daysOption = within(unitField).getByText(/Days?/);
|
||||
|
||||
// Let's turn on and set some invalid values.
|
||||
onField.props.onChange(onField.props.value.toString());
|
||||
valueField.props.onChange({ target: { value: "" } });
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
expect(
|
||||
within(generalContainer).queryAllByText("This field is required.").length
|
||||
).toBe(1);
|
||||
|
||||
// Let's change to sth valid.
|
||||
valueField.props.onChange({ target: { value: "30" } });
|
||||
unitField.props.onChange({
|
||||
target: { value: daysOption.props.value.toString() },
|
||||
});
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(valueField.props.disabled).toBe(true);
|
||||
expect(unitField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(valueField.props.disabled).toBe(false);
|
||||
expect(unitField.props.disabled).toBe(false);
|
||||
});
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
@@ -0,0 +1,293 @@
|
||||
import mockConsole from "jest-mock-console";
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import {
|
||||
createSinonStub,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
within,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import create from "../create";
|
||||
import { settings, users } from "../fixtures";
|
||||
|
||||
beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/moderation");
|
||||
// Test might pass even when it fails with errors in the log due to:
|
||||
// https://github.com/facebook/jest/issues/3917
|
||||
// We check the console to be error free..
|
||||
mockConsole("error");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Check that there are no errors in the console.
|
||||
// tslint:disable-next-line: no-console
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
me: sinon.stub().returns(users[0]),
|
||||
},
|
||||
};
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("configure-container")
|
||||
);
|
||||
const moderationContainer = await waitForElement(() =>
|
||||
within(configureContainer).getByTestID("configure-moderationContainer")
|
||||
);
|
||||
const saveChangesButton = within(configureContainer).getByTestID(
|
||||
"configure-sideBar-saveChanges"
|
||||
);
|
||||
return {
|
||||
testRenderer,
|
||||
configureContainer,
|
||||
moderationContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
|
||||
it("renders configure moderation", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
expect(within(configureContainer).toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("change akismet settings", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(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 {
|
||||
configureContainer,
|
||||
moderationContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const akismetContainer = within(moderationContainer).getByText(
|
||||
"Akismet Spam Detection Filter",
|
||||
{ selector: "fieldset" }
|
||||
);
|
||||
|
||||
const onField = within(akismetContainer).getByLabelText("On");
|
||||
const keyField = within(akismetContainer).getByLabelText("API Key");
|
||||
const siteField = within(akismetContainer).getByLabelText("Site URL");
|
||||
|
||||
// Let's turn it on.
|
||||
onField.props.onChange(onField.props.value.toString());
|
||||
|
||||
expect(saveChangesButton.props.disabled).toBe(false);
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
expect(
|
||||
within(akismetContainer).queryAllByText("This field is required.").length
|
||||
).toBe(2);
|
||||
|
||||
// Input valid api key
|
||||
keyField.props.onChange("my api key");
|
||||
|
||||
// Input malformed site.
|
||||
siteField.props.onChange("malformed url");
|
||||
|
||||
expect(
|
||||
within(akismetContainer).queryAllByText("This field is required.").length
|
||||
).toBe(0);
|
||||
expect(within(akismetContainer).queryAllByText("Invalid URL").length).toBe(1);
|
||||
|
||||
// Input correct site.
|
||||
siteField.props.onChange("https://coralproject.net");
|
||||
|
||||
expect(within(akismetContainer).queryAllByText("Invalid URL").length).toBe(0);
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(onField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(onField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change perspective settings", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(
|
||||
s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(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);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
}),
|
||||
s =>
|
||||
s.onSecondCall().callsFake((_: any, data: any) => {
|
||||
expect(
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
const perspectiveContainer = within(moderationContainer).getByText(
|
||||
"Perspective Toxic Comment Filter",
|
||||
{ selector: "fieldset" }
|
||||
);
|
||||
|
||||
const onField = within(perspectiveContainer).getByLabelText("On");
|
||||
const allowField = within(perspectiveContainer).getByLabelText("Allow");
|
||||
const keyField = within(perspectiveContainer).getByLabelText("API Key");
|
||||
const thresholdField = within(perspectiveContainer).getByLabelText(
|
||||
"Toxicity Threshold"
|
||||
);
|
||||
const endpointField = within(perspectiveContainer).getByLabelText(
|
||||
"Custom Endpoint"
|
||||
);
|
||||
|
||||
// Let's turn it on.
|
||||
onField.props.onChange(onField.props.value.toString());
|
||||
allowField.props.onChange(allowField.props.value.toString());
|
||||
|
||||
expect(saveChangesButton.props.disabled).toBe(false);
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
expect(
|
||||
within(perspectiveContainer).queryAllByText("This field is required.")
|
||||
.length
|
||||
).toBe(1);
|
||||
|
||||
// Input valid api key
|
||||
keyField.props.onChange("my api key");
|
||||
|
||||
// Input malformed endpoint.
|
||||
endpointField.props.onChange("malformed url");
|
||||
|
||||
// Input malformed threshold.
|
||||
thresholdField.props.onChange("abc");
|
||||
|
||||
expect(
|
||||
within(perspectiveContainer).queryAllByText("This field is required.")
|
||||
.length
|
||||
).toBe(0);
|
||||
expect(
|
||||
within(perspectiveContainer).queryAllByText("Invalid URL").length
|
||||
).toBe(1);
|
||||
expect(
|
||||
within(perspectiveContainer).queryAllByText(
|
||||
"Please enter a whole number between 0 and 100."
|
||||
).length
|
||||
).toBe(1);
|
||||
|
||||
// Input correct site.
|
||||
endpointField.props.onChange("https://custom-endpoint.net");
|
||||
|
||||
// Input valid threshold.
|
||||
thresholdField.props.onChange(10);
|
||||
|
||||
expect(
|
||||
within(perspectiveContainer).queryAllByText("Invalid URL").length
|
||||
).toBe(0);
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(onField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(onField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.calledOnce).toBe(true);
|
||||
|
||||
// Use default threshold.
|
||||
thresholdField.props.onChange("");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(onField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(onField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.calledTwice).toBe(true);
|
||||
});
|
||||
@@ -0,0 +1,197 @@
|
||||
import mockConsole from "jest-mock-console";
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import {
|
||||
createSinonStub,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
within,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import create from "../create";
|
||||
import { settings, users } from "../fixtures";
|
||||
|
||||
beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/organization");
|
||||
// Test might pass even when it fails with errors in the log due to:
|
||||
// https://github.com/facebook/jest/issues/3917
|
||||
// We check the console to be error free..
|
||||
mockConsole("error");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Check that there are no errors in the console.
|
||||
// tslint:disable-next-line: no-console
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
me: sinon.stub().returns(users[0]),
|
||||
},
|
||||
};
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("configure-container")
|
||||
);
|
||||
const organizationContainer = await waitForElement(() =>
|
||||
within(configureContainer).getByTestID("configure-organizationContainer")
|
||||
);
|
||||
const saveChangesButton = within(configureContainer).getByTestID(
|
||||
"configure-sideBar-saveChanges"
|
||||
);
|
||||
return {
|
||||
testRenderer,
|
||||
configureContainer,
|
||||
organizationContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
|
||||
it("renders configure organization", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
expect(within(configureContainer).toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("change organization name", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(data.input.settings.organizationName).toEqual("Coral Test");
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const {
|
||||
configureContainer,
|
||||
organizationContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const organizationNameField = within(organizationContainer).getByLabelText(
|
||||
"Organization Name"
|
||||
);
|
||||
|
||||
// Let's change some organization name.
|
||||
organizationNameField.props.onChange("");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Should show validation error.
|
||||
within(organizationContainer).getByText("This field is required.");
|
||||
|
||||
// Let's change to some valid organization name.
|
||||
organizationNameField.props.onChange("Coral Test");
|
||||
|
||||
// Should not show validation error.
|
||||
expect(
|
||||
within(organizationContainer).queryByText("This field is required.")
|
||||
).toBeNull();
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(organizationNameField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(organizationNameField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
|
||||
it("change organization contact email", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(data.input.settings.organizationContactEmail).toEqual(
|
||||
"test@coralproject.net"
|
||||
);
|
||||
settingsRecord = merge(settingsRecord, data.input.settings);
|
||||
return {
|
||||
settings: settingsRecord,
|
||||
clientMutationId: data.input.clientMutationId,
|
||||
};
|
||||
})
|
||||
);
|
||||
const {
|
||||
configureContainer,
|
||||
organizationContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const organizationEmailField = within(organizationContainer).getByLabelText(
|
||||
"Organization Email"
|
||||
);
|
||||
|
||||
// Let's change some organization name.
|
||||
organizationEmailField.props.onChange("");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Should show validation error.
|
||||
within(organizationContainer).getByText("This field is required.");
|
||||
|
||||
// Let's change to some valid organization name.
|
||||
organizationEmailField.props.onChange("test@coralproject.net");
|
||||
|
||||
// Should not show validation error.
|
||||
expect(
|
||||
within(organizationContainer).queryByText("This field is required.")
|
||||
).toBeNull();
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(organizationEmailField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(organizationEmailField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
@@ -0,0 +1,125 @@
|
||||
import mockConsole from "jest-mock-console";
|
||||
import { cloneDeep, get, merge } from "lodash";
|
||||
import sinon from "sinon";
|
||||
|
||||
import {
|
||||
createSinonStub,
|
||||
replaceHistoryLocation,
|
||||
wait,
|
||||
waitForElement,
|
||||
within,
|
||||
} from "talk-framework/testHelpers";
|
||||
|
||||
import create from "../create";
|
||||
import { settings, users } from "../fixtures";
|
||||
|
||||
beforeEach(() => {
|
||||
replaceHistoryLocation("http://localhost/admin/configure/wordList");
|
||||
// Test might pass even when it fails with errors in the log due to:
|
||||
// https://github.com/facebook/jest/issues/3917
|
||||
// We check the console to be error free..
|
||||
mockConsole("error");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Check that there are no errors in the console.
|
||||
// tslint:disable-next-line: no-console
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const createTestRenderer = async (resolver: any = {}) => {
|
||||
const resolvers = {
|
||||
...resolver,
|
||||
Query: {
|
||||
...resolver.Query,
|
||||
settings: sinon
|
||||
.stub()
|
||||
.returns(merge({}, settings, get(resolver, "Query.settings"))),
|
||||
me: sinon.stub().returns(users[0]),
|
||||
},
|
||||
};
|
||||
const { testRenderer } = create({
|
||||
// Set this to true, to see graphql responses.
|
||||
logNetwork: false,
|
||||
resolvers,
|
||||
initLocalState: localRecord => {
|
||||
localRecord.setValue(true, "loggedIn");
|
||||
},
|
||||
});
|
||||
const configureContainer = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("configure-container")
|
||||
);
|
||||
const wordListContainer = await waitForElement(() =>
|
||||
within(configureContainer).getByTestID("configure-wordListContainer")
|
||||
);
|
||||
const saveChangesButton = within(configureContainer).getByTestID(
|
||||
"configure-sideBar-saveChanges"
|
||||
);
|
||||
return {
|
||||
testRenderer,
|
||||
configureContainer,
|
||||
wordListContainer,
|
||||
saveChangesButton,
|
||||
};
|
||||
};
|
||||
|
||||
it("renders configure wordList", async () => {
|
||||
const { configureContainer } = await createTestRenderer();
|
||||
expect(within(configureContainer).toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("change banned and suspect words", async () => {
|
||||
let settingsRecord = cloneDeep(settings);
|
||||
const updateSettingsStub = createSinonStub(s =>
|
||||
s.onFirstCall().callsFake((_: any, data: any) => {
|
||||
expect(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 {
|
||||
configureContainer,
|
||||
wordListContainer,
|
||||
saveChangesButton,
|
||||
} = await createTestRenderer({
|
||||
Mutation: {
|
||||
updateSettings: updateSettingsStub,
|
||||
},
|
||||
});
|
||||
|
||||
const bannedField = within(wordListContainer).getByLabelText(
|
||||
"Banned Word List"
|
||||
);
|
||||
const suspectField = within(wordListContainer).getByLabelText(
|
||||
"Suspect Word List"
|
||||
);
|
||||
|
||||
// Let's change the wordlist contents.
|
||||
bannedField.props.onChange("Fuck\nAsshole");
|
||||
suspectField.props.onChange("idiot\nshame");
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
.getByType("form")
|
||||
.props.onSubmit();
|
||||
|
||||
// Submit button and text field should be disabled.
|
||||
expect(saveChangesButton.props.disabled).toBe(true);
|
||||
expect(bannedField.props.disabled).toBe(true);
|
||||
expect(suspectField.props.disabled).toBe(true);
|
||||
|
||||
// Wait for submission to be finished
|
||||
await wait(() => {
|
||||
expect(bannedField.props.disabled).toBe(false);
|
||||
expect(suspectField.props.disabled).toBe(false);
|
||||
});
|
||||
|
||||
// Should have successfully sent with server.
|
||||
expect(updateSettingsStub.called).toBe(true);
|
||||
});
|
||||
@@ -3,8 +3,31 @@ import { merge } from "lodash";
|
||||
export const settings = {
|
||||
id: "settings",
|
||||
wordList: {
|
||||
banned: [],
|
||||
suspect: [],
|
||||
suspect: ["idiot", "stupid"],
|
||||
banned: ["fuck"],
|
||||
},
|
||||
charCount: {
|
||||
enabled: false,
|
||||
max: 1000,
|
||||
min: 3,
|
||||
},
|
||||
closedTimeout: 604800,
|
||||
autoCloseStream: false,
|
||||
closedMessage: null,
|
||||
customCssUrl: null,
|
||||
domains: ["localhost:8080"],
|
||||
editCommentWindowLength: 30000,
|
||||
communityGuidelinesEnable: false,
|
||||
communityGuidelines: "",
|
||||
organizationContactEmail: "coral@test.com",
|
||||
organizationName: "Coral",
|
||||
integrations: {
|
||||
akismet: {
|
||||
enabled: false,
|
||||
},
|
||||
perspective: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
displayName: {
|
||||
|
||||
Reference in New Issue
Block a user