mirror of
https://github.com/wassname/talk.git
synced 2026-07-14 11:18:50 +08:00
[next] Auth Popup v2 (#2101)
* feat: Implement new Sign In view * feat: Move forgot + resetPassword to new design * feat: Implement sign up with new design * fix: narrow gutter * test: add unit tests * test: integration tests * feat: support show / hide password * feat: support oauth2 flow * feat: add views for user completion * feat: implement oauth2 sign up * test: fix snapshots * fix: lint * fix: get more complete mutation response * fix: removed array of OIDC integrations * fix: renamed resolver function * fix: adapt oidc client implementation * fix: targetFilter should be stream on signup * fix: removed unneeded message * fix: moved password into local profile * fix: made username optional, removed valid null value * fix: linting * fix: respect targetFilter * feat: support user registration mutations - Added `setUsername` - Added `setEmail` - Added `setPassword` - Added `permit` to `@auth` - Added `email` to `User` * fix: fixed issue with query * feat: added user password update * feat: complete sign in mutation * fix: adapt some rebasing gitches * test: improve tests * test: unittest for setting auth token * fix: failing tests * test: move most tests from enzyme to react-test-renderer * fix: remove schema warnings in tests * test: improve window mock * test: test different social login configurations * test: test social logins for sign up * fix: use htmlFor instead of for * test: more feature tests * feat: always go through account completion * test: feature test account completion * feat: addtional account completion test * Update start.ts * chore: refactor auth token retrieval logic
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { ReactTestInstance } from "react-test-renderer";
|
||||
|
||||
import { queryAllByText } from "./byText";
|
||||
import matchText, { TextMatchOptions, TextMatchPattern } from "./matchText";
|
||||
|
||||
const matcher = (pattern: TextMatchPattern, options?: TextMatchOptions) => (
|
||||
i: ReactTestInstance
|
||||
) => {
|
||||
const ariaLabelMatcher = (
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) => (i: ReactTestInstance) => {
|
||||
// Only look at dom components.
|
||||
if (typeof i.type !== "string" || !i.props["aria-label"]) {
|
||||
return false;
|
||||
@@ -20,31 +22,14 @@ export function getByLabelText(
|
||||
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;
|
||||
const results = queryAllByLabelText(container, pattern, options);
|
||||
if (results.length === 1) {
|
||||
return results[0];
|
||||
}
|
||||
}
|
||||
|
||||
export function queryAllByLabelText(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
try {
|
||||
return container.findAll(matcher(pattern, options));
|
||||
} catch {
|
||||
return [];
|
||||
if (results.length === 0) {
|
||||
throw new Error(`Could't find element with label text ${pattern}`);
|
||||
}
|
||||
throw new Error(`Found multiple elements with label text ${pattern}`);
|
||||
}
|
||||
|
||||
export function getAllByLabelText(
|
||||
@@ -52,5 +37,55 @@ export function getAllByLabelText(
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
return container.findAll(matcher(pattern, options));
|
||||
const results = queryAllByLabelText(container, pattern, options);
|
||||
if (results.length) {
|
||||
return results;
|
||||
}
|
||||
throw new Error(`Could't find element with label text ${pattern}`);
|
||||
}
|
||||
|
||||
export function queryByLabelText(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
const results = queryAllByLabelText(container, pattern, options);
|
||||
if (results.length) {
|
||||
return results[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function queryAllByLabelText(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
const matches = container.findAll(ariaLabelMatcher(pattern, options));
|
||||
queryAllByText(container, pattern).forEach(i => {
|
||||
if (typeof i.type !== "string") {
|
||||
return;
|
||||
}
|
||||
if (i.props.id) {
|
||||
try {
|
||||
matches.push(
|
||||
container.find(
|
||||
x =>
|
||||
typeof x.type === "string" &&
|
||||
x.props["aria-labelledby"] === i.props.id
|
||||
)
|
||||
);
|
||||
} catch {} // tslint:disable-line:no-empty
|
||||
}
|
||||
if (i.type === "label" && i.props.htmlFor) {
|
||||
try {
|
||||
matches.push(
|
||||
container.find(
|
||||
x => typeof x.type === "string" && x.props.id === i.props.htmlFor
|
||||
)
|
||||
);
|
||||
} catch {} // tslint:disable-line:no-empty
|
||||
}
|
||||
});
|
||||
return matches;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ const matcher = (pattern: TextMatchPattern, options?: TextMatchOptions) => (
|
||||
i: ReactTestInstance
|
||||
) => {
|
||||
// Only look at dom components.
|
||||
if (typeof i.type !== "string" || !i.props["data-test"]) {
|
||||
if (typeof i.type !== "string" || !i.props["data-testid"]) {
|
||||
return false;
|
||||
}
|
||||
return matchText(pattern, i.props["data-test"], {
|
||||
return matchText(pattern, i.props["data-testid"], {
|
||||
collapseWhitespace: false,
|
||||
...options,
|
||||
});
|
||||
@@ -23,34 +23,34 @@ export function getByTestID(
|
||||
return container.find(matcher(pattern, options));
|
||||
}
|
||||
|
||||
export function getAllByTestID(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
const results = container.findAll(matcher(pattern, options));
|
||||
if (!results.length) {
|
||||
throw new Error(`Couldn't find test id ${pattern}`);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
export function queryByTestID(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
try {
|
||||
return container.find(matcher(pattern, options));
|
||||
} catch {
|
||||
const results = container.findAll(matcher(pattern, options));
|
||||
if (!results.length) {
|
||||
return null;
|
||||
}
|
||||
return results[0];
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -30,34 +30,34 @@ export function getByText(
|
||||
return container.find(matcher(pattern, options));
|
||||
}
|
||||
|
||||
export function getAllByText(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
const results = container.findAll(matcher(pattern, options));
|
||||
if (!results.length) {
|
||||
throw new Error(`Couldn't find text ${pattern}`);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
export function queryByText(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
try {
|
||||
return container.find(matcher(pattern, options));
|
||||
} catch {
|
||||
const results = container.findAll(matcher(pattern, options));
|
||||
if (!results.length) {
|
||||
return null;
|
||||
}
|
||||
return results[0];
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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") {
|
||||
return false;
|
||||
}
|
||||
return matchText(pattern, i.type, {
|
||||
collapseWhitespace: false,
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
export function getByType(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
return container.find(matcher(pattern, options));
|
||||
}
|
||||
|
||||
export function getAllByType(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
const results = container.findAll(matcher(pattern, options));
|
||||
if (!results.length) {
|
||||
throw new Error(`Couldn't find test id ${pattern}`);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
export function queryByType(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
const results = container.findAll(matcher(pattern, options));
|
||||
if (!results.length) {
|
||||
return null;
|
||||
}
|
||||
return results[0];
|
||||
}
|
||||
|
||||
export function queryAllByType(
|
||||
container: ReactTestInstance,
|
||||
pattern: TextMatchPattern,
|
||||
options?: TextMatchOptions
|
||||
) {
|
||||
return container.findAll(matcher(pattern, options));
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
export default function createAuthToken() {
|
||||
return `${btoa(
|
||||
JSON.stringify({
|
||||
alg: "HS256",
|
||||
typ: "JWT",
|
||||
})
|
||||
)}.${btoa(
|
||||
JSON.stringify({
|
||||
jti: "31b26591-4e9a-4388-a7ff-e1bdc5d97cce",
|
||||
})
|
||||
)}`;
|
||||
}
|
||||
@@ -26,6 +26,8 @@ export interface CreateRelayEnvironmentNetworkParams {
|
||||
resolvers: IResolvers<any, any>;
|
||||
/** If enabled, graphql responses will be logged to the console */
|
||||
logNetwork?: boolean;
|
||||
/** If enabled, graphql errors will be muted */
|
||||
muteNetworkErrors?: boolean;
|
||||
}
|
||||
|
||||
export interface CreateRelayEnvironmentParams {
|
||||
@@ -58,10 +60,14 @@ export default function createRelayEnvironment(
|
||||
if (params.network) {
|
||||
const schema = loadSchema(
|
||||
params.network.projectName,
|
||||
params.network.resolvers
|
||||
params.network.resolvers,
|
||||
{ requireResolversForResolveType: false }
|
||||
);
|
||||
network = Network.create(
|
||||
wrapFetchWithLogger(createFetch({ schema }), params.network.logNetwork)
|
||||
wrapFetchWithLogger(createFetch({ schema }), {
|
||||
logResult: params.network.logNetwork,
|
||||
muteErrors: params.network.muteNetworkErrors,
|
||||
})
|
||||
);
|
||||
}
|
||||
const environment = new Environment({
|
||||
|
||||
@@ -10,25 +10,13 @@ export {
|
||||
} from "./removeFragmentRefs";
|
||||
export { default as createUUIDGenerator } from "./createUUIDGenerator";
|
||||
export * from "./denormalize";
|
||||
export { default as replaceHistoryLocation } from "./replaceHistoryLocation";
|
||||
export { default as limitSnapshotTo } from "./limitSnapshotTo";
|
||||
export { default as inputPredicate } from "./inputPredicate";
|
||||
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";
|
||||
export { default as replaceHistoryLocation } from "./replaceHistoryLocation";
|
||||
export { default as createAuthToken } from "./createAuthToken";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export default function limitSnapshotTo(dataTest: string, node: any) {
|
||||
if (node.props && node.props["data-test"] === dataTest) {
|
||||
if (node.props && node.props["data-testid"] === dataTest) {
|
||||
return node;
|
||||
}
|
||||
if (node.children) {
|
||||
|
||||
@@ -13,6 +13,12 @@ import {
|
||||
queryByTestID,
|
||||
} from "./byTestID";
|
||||
import { getAllByText, getByText, queryAllByText, queryByText } from "./byText";
|
||||
import {
|
||||
getAllByType,
|
||||
getByType,
|
||||
queryAllByType,
|
||||
queryByType,
|
||||
} from "./byType";
|
||||
import toJSON from "./toJSON";
|
||||
|
||||
type Func0<R> = () => R;
|
||||
@@ -49,6 +55,10 @@ export default function within(container: ReactTestInstance) {
|
||||
getAllByLabelText: applyContainer(container, getAllByLabelText),
|
||||
queryByLabelText: applyContainer(container, queryByLabelText),
|
||||
queryAllByLabelText: applyContainer(container, queryAllByLabelText),
|
||||
getByType: applyContainer(container, getByType),
|
||||
getAllByType: applyContainer(container, getAllByType),
|
||||
queryByType: applyContainer(container, queryByType),
|
||||
queryAllByType: applyContainer(container, queryAllByType),
|
||||
toJSON: () => toJSON(container),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user