[next] Moderate (#2118)

* fix: load .env before building / watching

* feat: Implement AppBar, Brand, and SubBar

* feat: add card ui component

* feat: add modqueue components

* feat: implement modqueue

* feat: add translations

* test: add unit tests

* feat: single comment view

* test: feature / integration tests for modqueue

* test: fix remaining tests

* feature: support TextMatchOptions

* fix: remove body count marker

* fix: remove accidently added package

* feat: testHelper toJSON

* chore: cleanup + comments

* chore: better types

* test: fix test

* chore: refactor decision history test

* chore: tiny fix

* fix: adjust to recent server changes

* fix: marking suspect and banned words

* feat: added moderation queue edge to accept/reject comment payloads

- Simplified moderationQueue returns
- Simplified resolvers

* feat: update counts

* feat: added id's to moderation queue and settings

* fix+test: test count changes, apply fix

* chore: adapt to server change, and remove custom mutation handlers

* fix: use common utils

* fix: purify fix, babel fix

* fix: workaround css treeshake issue and upgrade css plugins

* fix: fixed snapshot

* fix: support empty word lists

* feat: separate client config
This commit is contained in:
Kiwi
2018-12-18 18:00:39 +00:00
committed by Wyatt Johnson
parent 90e67ca479
commit 1fc49f8e50
316 changed files with 11587 additions and 3005 deletions
@@ -0,0 +1,56 @@
import { ReactTestInstance } from "react-test-renderer";
import matchText, { TextMatchOptions, TextMatchPattern } from "./matchText";
const matcher = (pattern: TextMatchPattern, options?: TextMatchOptions) => (
i: ReactTestInstance
) => {
// Only look at dom components.
if (typeof i.type !== "string" || !i.props["aria-label"]) {
return false;
}
return matchText(pattern, i.props["aria-label"], {
collapseWhitespace: false,
...options,
});
};
export function getByLabelText(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
return container.find(matcher(pattern, options));
}
export function queryByLabelText(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
try {
return container.find(matcher(pattern, options));
} catch {
return null;
}
}
export function queryAllByLabelText(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
try {
return container.findAll(matcher(pattern, options));
} catch {
return [];
}
}
export function getAllByLabelText(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
return container.findAll(matcher(pattern, options));
}
@@ -0,0 +1,56 @@
import { ReactTestInstance } from "react-test-renderer";
import matchText, { TextMatchOptions, TextMatchPattern } from "./matchText";
const matcher = (pattern: TextMatchPattern, options?: TextMatchOptions) => (
i: ReactTestInstance
) => {
// Only look at dom components.
if (typeof i.type !== "string" || !i.props["data-test"]) {
return false;
}
return matchText(pattern, i.props["data-test"], {
collapseWhitespace: false,
...options,
});
};
export function getByTestID(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
return container.find(matcher(pattern, options));
}
export function queryByTestID(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
try {
return container.find(matcher(pattern, options));
} catch {
return null;
}
}
export function queryAllByTestID(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
try {
return container.findAll(matcher(pattern, options));
} catch {
return [];
}
}
export function getAllByTestID(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
return container.findAll(matcher(pattern, options));
}
@@ -0,0 +1,63 @@
import React from "react";
import { ReactTestInstance } from "react-test-renderer";
import matchText, { TextMatchOptions, TextMatchPattern } from "./matchText";
const matcher = (pattern: TextMatchPattern, options?: TextMatchOptions) => (
i: ReactTestInstance
) => {
// Only look at dom components.
if (typeof i.type !== "string") {
return false;
}
if (!i.props.children) {
return false;
}
const children = React.Children.toArray(i.props.children);
for (const c of children) {
if (typeof c === "string" && matchText(pattern, c, options)) {
return true;
}
}
return false;
};
export function getByText(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
return container.find(matcher(pattern, options));
}
export function queryByText(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
try {
return container.find(matcher(pattern, options));
} catch {
return null;
}
}
export function queryAllByText(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
try {
return container.findAll(matcher(pattern, options));
} catch {
return [];
}
}
export function getAllByText(
container: ReactTestInstance,
pattern: TextMatchPattern,
options?: TextMatchOptions
) {
return container.findAll(matcher(pattern, options));
}
@@ -1,5 +0,0 @@
import { ReactTestInstance } from "react-test-renderer";
export default function getByTestID(id: string, instance: ReactTestInstance) {
return instance.findByProps({ "data-test": id });
}
@@ -1,20 +0,0 @@
import React from "react";
import { ReactTestInstance } from "react-test-renderer";
export default function getByText(text: string, instance: ReactTestInstance) {
return instance.find(i => {
if (!i.props.children) {
return false;
}
const children = React.Children.toArray(i.props.children);
for (const c of children) {
if (
typeof c === "string" &&
c.toLowerCase().includes(text.toLowerCase())
) {
return true;
}
}
return false;
});
}
+17 -2
View File
@@ -13,7 +13,22 @@ export * from "./denormalize";
export { default as replaceHistoryLocation } from "./replaceHistoryLocation";
export { default as limitSnapshotTo } from "./limitSnapshotTo";
export { default as inputPredicate } from "./inputPredicate";
export { default as getByTestID } from "./getByTestID";
export { default as getByText } from "./getByText";
export {
getByTestID,
getAllByTestID,
queryByTestID,
queryAllByTestID,
} from "./byTestID";
export { getByText, getAllByText, queryByText, queryAllByText } from "./byText";
export {
getByLabelText,
getAllByLabelText,
queryByLabelText,
queryAllByLabelText,
} from "./byLabelText";
export { default as within } from "./within";
export { default as wait } from "./wait";
export { default as waitForElement } from "./waitForElement";
export { default as waitUntilThrow } from "./waitUntilThrow";
export { default as matchText } from "./matchText";
export { default as toJSON } from "./toJSON";
@@ -0,0 +1,34 @@
export interface TextMatchOptions {
exact?: boolean; // defaults to true
collapseWhitespace?: boolean; // defaults to true
trim?: boolean; // defaults to true
}
export type TextMatchPattern = string | RegExp;
export default function matchText(
pattern: TextMatchPattern,
text: string,
options: TextMatchOptions = {}
) {
if (typeof pattern === "string") {
let a = text;
let b = pattern;
if (options.trim || options.trim === undefined) {
a = a.trim();
b = b.trim();
}
if (
options.collapseWhitespace ||
options.collapseWhitespace === undefined
) {
a = a.replace(/\s+/g, " ");
b = b.replace(/\s+/g, " ");
}
if (options.exact || options.exact === undefined) {
return a === b;
}
return text.toLowerCase().includes(pattern.toLowerCase());
}
return pattern.test(text);
}
@@ -0,0 +1,57 @@
import { ReactTestInstance } from "react-test-renderer";
interface ReactTestRendererJSON {
type: string;
props: { [propName: string]: any };
children: null | ReactTestRendererNode[];
$$typeof?: symbol; // Optional because we add it with defineProperty().
}
type ReactTestRendererNode = ReactTestRendererJSON | string;
export function toJSONRecursive(
inst: ReactTestInstance
): ReactTestRendererNode[] | null {
const { children: _, ...props }: any = inst.props || {};
let renderedChildren = null;
if (inst.children) {
for (const child of inst.children) {
const renderedChild =
typeof child === "string" ? [child] : toJSONRecursive(child);
if (renderedChild !== null) {
if (renderedChildren === null) {
renderedChildren = [...renderedChild];
} else {
renderedChildren.push(...renderedChild);
}
}
}
}
if (typeof inst.type === "string") {
const json: ReactTestRendererJSON = {
type: inst.type,
props,
children: renderedChildren,
};
Object.defineProperty(json, "$$typeof", {
value: Symbol.for("react.test.json"),
});
return [json];
}
return renderedChildren;
}
/**
* Turns a ReactTestInstance into JSON for snapshotting purposes.
*/
export default function toJSON(
inst: ReactTestInstance
): ReactTestRendererNode | ReactTestRendererNode[] | null {
const result = toJSONRecursive(inst);
if (!result) {
return null;
}
if (result.length === 1) {
return result[0];
}
return result;
}
@@ -0,0 +1,17 @@
import { ReactTestInstance } from "react-test-renderer";
import wait from "./wait";
interface Options {
timeout?: number;
interval?: number;
}
export default async function waitUntilThrow(
callback: () => ReactTestInstance | null,
options?: Options
): Promise<void> {
await wait(() => {
expect(callback).toThrow();
}, options);
}
@@ -0,0 +1,54 @@
import { ReactTestInstance } from "react-test-renderer";
import {
getAllByLabelText,
getByLabelText,
queryAllByLabelText,
queryByLabelText,
} from "./byLabelText";
import {
getAllByTestID,
getByTestID,
queryAllByTestID,
queryByTestID,
} from "./byTestID";
import { getAllByText, getByText, queryAllByText, queryByText } from "./byText";
import toJSON from "./toJSON";
type Func0<R> = () => R;
type Func1<A, R> = (a?: A) => R;
type Func2<A, B, R> = (a: A, b?: B) => R;
type Func3<A, B, C, R> = (a: A, b: B, c?: C) => R;
type RemoveFirstArgument<T, R> =
T extends [any, any, any, any?] ? Func3<T[1], T[2], T[3], R> :
T extends [any, any, any?] ? Func2<T[1], T[2], R> :
T extends [any, any?] ? Func1<T[1], R> :
T extends [any] ? Func0<R> :
unknown
;
// tslint:disable
// @TODO: currently tslint fails to parse this: `...any[]`.
function applyContainer<T extends [ReactTestInstance, ...any[]], R>(container: ReactTestInstance, fn: (...args: T) => R): RemoveFirstArgument<T, R> {
return ((...args: any[]) => fn(...[container, ...args] as any)) as any;
}
// tslint:enable
export default function within(container: ReactTestInstance) {
return {
getByTestID: applyContainer(container, getByTestID),
getAllByTestID: applyContainer(container, getAllByTestID),
queryByTestID: applyContainer(container, queryByTestID),
queryAllByTestID: applyContainer(container, queryAllByTestID),
getByText: applyContainer(container, getByText),
getAllByText: applyContainer(container, getAllByText),
queryByText: applyContainer(container, queryByText),
queryAllByText: applyContainer(container, queryAllByText),
getByLabelText: applyContainer(container, getByLabelText),
getAllByLabelText: applyContainer(container, getAllByLabelText),
queryByLabelText: applyContainer(container, queryByLabelText),
queryAllByLabelText: applyContainer(container, queryAllByLabelText),
toJSON: () => toJSON(container),
}
}