-
Notifications
You must be signed in to change notification settings - Fork 155
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Add integ tests for single page funnels
This adds tests for the existing behaviour. It includes some fix mes that were found while writing and is intended as a start to testing.
- Loading branch information
1 parent
7fa1db8
commit 20b0765
Showing
5 changed files
with
730 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import { IFunnelMetrics } from '~components/internal/analytics/interfaces'; | ||
|
||
const funnelMetricsLog: { action: string; resolvedProps?: any; props: any }[] = []; | ||
(window as any).__awsuiFunnelMetrics__ = funnelMetricsLog; | ||
|
||
export const MockedFunnelMetrics: IFunnelMetrics = { | ||
funnelStart(props): string { | ||
const funnelName = document.querySelector(props.funnelNameSelector)!.innerHTML; | ||
funnelMetricsLog.push({ action: 'funnelStart', props, resolvedProps: { funnelName } }); | ||
return 'mocked-funnel-id'; | ||
}, | ||
|
||
funnelError(props): void { | ||
funnelMetricsLog.push({ action: 'funnelError', props }); | ||
}, | ||
|
||
funnelComplete(props): void { | ||
funnelMetricsLog.push({ action: 'funnelComplete', props }); | ||
}, | ||
|
||
funnelSuccessful(props): void { | ||
funnelMetricsLog.push({ action: 'funnelSuccessful', props }); | ||
}, | ||
|
||
funnelCancelled(props): void { | ||
funnelMetricsLog.push({ action: 'funnelCancelled', props }); | ||
}, | ||
|
||
funnelChange(props): void { | ||
funnelMetricsLog.push({ action: 'funnelChange', props }); | ||
}, | ||
|
||
funnelStepStart(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)!.innerHTML; | ||
funnelMetricsLog.push({ action: 'funnelStepStart', props, resolvedProps: { stepName } }); | ||
}, | ||
|
||
funnelStepComplete(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)!.innerHTML; | ||
funnelMetricsLog.push({ action: 'funnelStepComplete', props, resolvedProps: { stepName } }); | ||
}, | ||
|
||
funnelStepNavigation(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)!.innerHTML; | ||
// const subStepAllElements = document.querySelectorAll(props.subStepAllSelector); // TODO: Does not work | ||
|
||
funnelMetricsLog.push({ action: 'funnelStepNavigation', props, resolvedProps: { stepName } }); | ||
}, | ||
|
||
funnelStepError(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)!.innerHTML; | ||
funnelMetricsLog.push({ action: 'funnelStepError', props, resolvedProps: { stepName } }); | ||
}, | ||
|
||
funnelStepChange(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)!.innerHTML; | ||
funnelMetricsLog.push({ action: 'funnelStepChange', props, resolvedProps: { stepName } }); | ||
}, | ||
|
||
funnelSubStepStart(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)!.innerHTML; | ||
const subStepName = document.querySelector(props.subStepNameSelector)!.innerHTML; | ||
const subStepAllElements = document.querySelectorAll(props.subStepAllSelector); | ||
const subStepElement = document.querySelector(props.subStepSelector); | ||
|
||
funnelMetricsLog.push({ | ||
action: 'funnelSubStepStart', | ||
props, | ||
resolvedProps: { stepName, subStepName, subStepAllElements, subStepElement }, | ||
}); | ||
}, | ||
|
||
funnelSubStepComplete(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)?.innerHTML; | ||
const subStepName = document.querySelector(props.subStepNameSelector)?.innerHTML; | ||
const subStepAllElements = document.querySelectorAll(props.subStepAllSelector); | ||
const subStepElement = document.querySelector(props.subStepSelector); | ||
|
||
funnelMetricsLog.push({ | ||
action: 'funnelSubStepComplete', | ||
props, | ||
resolvedProps: { stepName, subStepName, subStepAllElements, subStepElement }, | ||
}); | ||
}, | ||
|
||
funnelSubStepError(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)!.innerHTML; | ||
const subStepName = document.querySelector(props.subStepNameSelector)!.innerHTML; | ||
const fieldLabel = document.querySelector(props.fieldLabelSelector!)!.innerHTML; | ||
const fieldError = document.querySelector(props.fieldErrorSelector!)!.innerHTML; | ||
|
||
funnelMetricsLog.push({ | ||
action: 'funnelSubStepError', | ||
props, | ||
resolvedProps: { fieldLabel, fieldError, stepName, subStepName }, | ||
}); | ||
}, | ||
|
||
helpPanelInteracted(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)!.innerHTML; | ||
const subStepName = document.querySelector(props.subStepNameSelector)!.innerHTML; | ||
const subStepElement = document.querySelectorAll(props.subStepSelector); | ||
const subStepAllElements = document.querySelectorAll(props.subStepAllSelector); | ||
const element = document.querySelector(props.elementSelector); | ||
|
||
funnelMetricsLog.push({ | ||
action: 'helpPanelInteracted', | ||
props, | ||
resolvedProps: { stepName, subStepName, subStepAllElements, element, subStepElement }, | ||
}); | ||
}, | ||
|
||
externalLinkInteracted(props): void { | ||
const stepName = document.querySelector(props.stepNameSelector)!.innerHTML; | ||
const subStepName = document.querySelector(props.subStepNameSelector)!.innerHTML; | ||
const subStepElement = document.querySelectorAll(props.subStepSelector); | ||
const subStepAllElements = document.querySelectorAll(props.subStepAllSelector); | ||
const element = document.querySelector(props.elementSelector); | ||
|
||
funnelMetricsLog.push({ | ||
action: 'externalLinkInteracted', | ||
props, | ||
resolvedProps: { stepName, subStepName, subStepAllElements, element, subStepElement }, | ||
}); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
import React, { useState } from 'react'; | ||
import { | ||
AppLayout, | ||
BreadcrumbGroup, | ||
Button, | ||
Container, | ||
Form, | ||
FormField, | ||
Header, | ||
Input, | ||
Link, | ||
Modal, | ||
NonCancelableCustomEvent, | ||
S3ResourceSelector, | ||
S3ResourceSelectorProps, | ||
SpaceBetween, | ||
} from '~components'; | ||
|
||
import { fetchBuckets, fetchObjects, fetchVersions } from '../s3-resource-selector/data/request'; | ||
import { i18nStrings } from '../s3-resource-selector/data/i18n-strings'; | ||
import { SelfDismissibleAlert, uriToConsoleUrl } from '../s3-resource-selector/shared'; | ||
|
||
import { setFunnelMetrics } from '~components/internal/analytics'; | ||
import { MockedFunnelMetrics } from './mock-funnel'; | ||
|
||
setFunnelMetrics(MockedFunnelMetrics); | ||
|
||
export default function SinglePageCreate() { | ||
const [mounted, setUnmounted] = useState(true); | ||
const [modalVisible, setModalVisible] = useState(false); | ||
const [value, setValue] = useState(''); | ||
const [errorText, setErrorText] = useState(''); | ||
const [validationError, setValidationError] = useState<string | undefined>(); | ||
const [fetchError, setFetchError] = useState<string | null>(null); | ||
const [resource, setResource] = useState<S3ResourceSelectorProps.Resource>({ uri: '' }); | ||
|
||
function wrapWithErrorHandler<T extends (...args: any[]) => Promise<unknown>>(callback: T): T { | ||
return ((...args) => { | ||
setFetchError(null); | ||
return callback(...args).catch(error => { | ||
setFetchError(error.message); | ||
throw error; | ||
}); | ||
}) as T; | ||
} | ||
|
||
const s3ResourceSelectorProps: S3ResourceSelectorProps = { | ||
resource, | ||
viewHref: resource?.uri !== '' && !validationError ? uriToConsoleUrl(resource.uri) : '', | ||
alert: fetchError && ( | ||
<SelfDismissibleAlert type="error" header="Data fetching error"> | ||
{fetchError} | ||
</SelfDismissibleAlert> | ||
), | ||
invalid: !!validationError, | ||
selectableItemsTypes: ['objects', 'versions'], | ||
bucketsVisibleColumns: ['CreationDate', 'Region', 'Name'], | ||
objectsIsItemDisabled: object => !!object.IsFolder, | ||
i18nStrings, | ||
fetchBuckets: wrapWithErrorHandler(fetchBuckets), | ||
fetchObjects: wrapWithErrorHandler(fetchObjects), | ||
fetchVersions: wrapWithErrorHandler(fetchVersions), | ||
onChange: ({ detail }: NonCancelableCustomEvent<S3ResourceSelectorProps.ChangeDetail>) => { | ||
setResource(detail.resource); | ||
setValidationError(detail.errorText); | ||
}, | ||
}; | ||
|
||
return ( | ||
<AppLayout | ||
breadcrumbs={ | ||
<BreadcrumbGroup | ||
items={[ | ||
{ text: 'System', href: '#' }, | ||
{ text: 'Components', href: '#components' }, | ||
{ | ||
text: 'Create Resource', | ||
href: '#components/breadcrumb-group', | ||
}, | ||
]} | ||
ariaLabel="Breadcrumbs" | ||
/> | ||
} | ||
content={ | ||
<> | ||
<button data-testid="unmount" onClick={() => setUnmounted(false)}> | ||
Unmount | ||
</button> | ||
<button data-testid="embedded-form-modal" onClick={() => setModalVisible(true)}> | ||
Open Modal | ||
</button> | ||
{modalVisible && ( | ||
<Modal header="Modal title" visible={modalVisible}> | ||
<Form>I am a form</Form> | ||
</Modal> | ||
)} | ||
{mounted && ( | ||
<Form | ||
errorText={errorText} | ||
actions={ | ||
<SpaceBetween size="xs" direction="horizontal"> | ||
<Button data-testid="cancel" onClick={() => setUnmounted(false)}> | ||
Cancel | ||
</Button> | ||
<Button | ||
data-testid="submit" | ||
variant="primary" | ||
onClick={() => { | ||
if (value === 'error') { | ||
setErrorText('There is an error'); | ||
} else { | ||
setErrorText(''); | ||
setUnmounted(false); | ||
} | ||
}} | ||
> | ||
Submit | ||
</Button> | ||
</SpaceBetween> | ||
} | ||
header={ | ||
<Header variant="h1" info={<Link>Info</Link>} description="Form header description"> | ||
Form Header | ||
</Header> | ||
} | ||
> | ||
<SpaceBetween size="m"> | ||
<Container | ||
header={ | ||
<Header variant="h2" description="Container 1 - description"> | ||
Container 1 - header | ||
</Header> | ||
} | ||
> | ||
<SpaceBetween size="s"> | ||
<FormField | ||
info={ | ||
<Link data-testid="external-link" external={true} href="#"> | ||
Learn more | ||
</Link> | ||
} | ||
errorText={value === 'error' ? 'Trigger error' : ''} | ||
label="This is an ordinary text field" | ||
> | ||
<Input | ||
data-testid="field1" | ||
value={value} | ||
onChange={event => { | ||
setValue(event.detail.value); | ||
}} | ||
/> | ||
</FormField> | ||
</SpaceBetween> | ||
</Container> | ||
<Container | ||
header={ | ||
<Header variant="h2" description="Container 2 - description"> | ||
Container 2 - header | ||
</Header> | ||
} | ||
> | ||
<FormField | ||
info={ | ||
<Link data-testid="info-link" variant="info"> | ||
Info | ||
</Link> | ||
} | ||
label="Read audio files from S3" | ||
description="Choose an audio file in Amazon S3. Amazon S3 is object storage built to store and retrieve data." | ||
constraintText="Format: s3://bucket/prefix/object. For objects in a bucket with versioning enabled, you can choose the most recent or a previous version of the object." | ||
errorText={validationError} | ||
stretch={true} | ||
> | ||
<S3ResourceSelector {...s3ResourceSelectorProps} /> | ||
</FormField> | ||
</Container> | ||
</SpaceBetween> | ||
</Form> | ||
)} | ||
</> | ||
} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
import React from 'react'; | ||
import Alert, { AlertProps } from '~components/alert'; | ||
|
||
export function SelfDismissibleAlert(props: Omit<AlertProps, 'visible' | 'onDismiss'>) { | ||
const [visible, setVisible] = React.useState(true); | ||
return <Alert {...props} visible={visible} dismissible={true} onDismiss={() => setVisible(false)} />; | ||
} | ||
|
||
export function uriToConsoleUrl(uri: string) { | ||
const prefix = 'https://s3.console.aws.amazon.com/s3/buckets/'; | ||
return uri.replace(/^s3:\/\//, prefix); | ||
} |
Oops, something went wrong.