[next] Auth Popup v2 (#2101)

* feat: Implement new Sign In view

* feat: Move forgot + resetPassword to new design

* feat: Implement sign up with new design

* fix: narrow gutter

* test: add unit tests

* test: integration tests

* feat: support show / hide password

* feat: support oauth2 flow

* feat: add views for user completion

* feat: implement oauth2 sign up

* test: fix snapshots

* fix: lint

* fix: get more complete mutation response

* fix: removed array of OIDC integrations

* fix: renamed resolver function

* fix: adapt oidc client implementation

* fix: targetFilter should be stream on signup

* fix: removed unneeded message

* fix: moved password into local profile

* fix: made username optional, removed valid null value

* fix: linting

* fix: respect targetFilter

* feat: support user registration mutations

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

* fix: fixed issue with query

* feat: added user password update

* feat: complete sign in mutation

* fix: adapt some rebasing gitches

* test: improve tests

* test: unittest for setting auth token

* fix: failing tests

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

* fix: remove schema warnings in tests

* test: improve window mock

* test: test different social login configurations

* test: test social logins for sign up

* fix: use htmlFor instead of for

* test: more feature tests

* feat: always go through account completion

* test: feature test account completion

* feat: addtional account completion test

* Update start.ts

* chore: refactor auth token retrieval logic
This commit is contained in:
Kiwi
2018-12-20 22:32:04 +01:00
committed by GitHub
parent 326a10dc5d
commit 065cb4b03a
331 changed files with 12476 additions and 7163 deletions
@@ -1,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));
}
+15 -15
View File
@@ -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({
+2 -14
View File
@@ -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),
}
}