add teardown and data-id for quick-dapp e2e

pull/5060/head
drafish 4 months ago committed by yann300
parent 4a0f3a5a9d
commit b00bd7e349
  1. 42
      apps/quick-dapp/src/actions/index.ts
  2. 4
      apps/quick-dapp/src/components/ContractGUI/index.tsx
  3. 75
      apps/quick-dapp/src/components/DeployPanel/index.tsx
  4. 3
      apps/quick-dapp/src/components/DeployPanel/theme.tsx
  5. 2
      apps/quick-dapp/src/components/EditInstance/index.tsx
  6. 2
      apps/quick-dapp/src/components/ImageUpload/index.tsx
  7. 6
      apps/quick-dapp/src/components/MultipleContainers/components/Container/Container.tsx
  8. 5
      apps/quick-dapp/src/components/MultipleContainers/components/Item/Item.tsx
  9. 9
      apps/quick-dapp/src/components/MultipleContainers/index.tsx
  10. 2
      apps/remix-ide/src/app/tabs/locales/en/quickDapp.json
  11. 1
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx

@ -244,8 +244,50 @@ export const deploy = async (payload: any, callback: any) => {
} catch (error) {}
callback({ code: 'ERROR', error: 'deploy failed, please try again' });
return;
};
export const teardown = async (payload: any, callback: any) => {
const surgeToken = localStorage.getItem('__SURGE_TOKEN');
const surgeEmail = localStorage.getItem('__SURGE_EMAIL');
let isLogin = false;
if (surgeToken && surgeEmail === payload.email) {
try {
await surgeClient.whoami();
isLogin = true;
} catch (error) {
/* empty */
}
}
if (!isLogin) {
try {
await surgeClient.login({
user: payload.email,
password: payload.password,
});
localStorage.setItem('__SURGE_EMAIL', payload.email);
localStorage.setItem('__SURGE_PASSWORD', payload.password);
localStorage.setItem('__DISQUS_SHORTNAME', payload.shortname);
} catch (error: any) {
callback({ code: 'ERROR', error: error.message });
return;
}
}
try {
await surgeClient.teardown(`${payload.subdomain}.surge.sh`);
} catch ({ message }: any) {
if (message === '403') {
callback({ code: 'ERROR', error: 'this domain belongs to someone else' });
} else {
callback({ code: 'ERROR', error: 'gateway timeout, please try again' });
}
return;
}
callback({ code: 'SUCCESS', error: '' });
return;
}
export const initInstance = async ({
methodIdentifiers,
devdoc,

@ -12,7 +12,7 @@ const getFuncABIInputs = (funABI: any) => {
return txHelper.inputParametersDeclarationToString(funABI.inputs);
};
export function ContractGUI(props: { funcABI: any }) {
export function ContractGUI(props: { funcABI: any, funcId: any }) {
const intl = useIntl()
const isConstant =
props.funcABI.constant !== undefined ? props.funcABI.constant : false;
@ -69,6 +69,7 @@ export function ContractGUI(props: { funcABI: any }) {
<div className={`d-inline-block`} style={{ width: '90%' }}>
<div className="p-2">
<input
data-id={`functionTitle${props.funcId}`}
className="form-control"
placeholder={intl.formatMessage({ id: 'quickDapp.functionTitle' })}
value={props.funcABI.title}
@ -117,6 +118,7 @@ export function ContractGUI(props: { funcABI: any }) {
</div>
<div className="p-2">
<textarea
data-id={`functionInstructions${props.funcId}`}
className="form-control"
placeholder={intl.formatMessage({ id: 'quickDapp.functionInstructions' })}
value={props.funcABI.details}

@ -1,8 +1,9 @@
import React, { useContext, useState } from 'react';
import React, { useContext, useState, useEffect } from 'react';
import { Form, Button, Alert, InputGroup } from 'react-bootstrap';
import { FormattedMessage, useIntl } from 'react-intl';
import {
deploy,
teardown,
emptyInstance,
resetInstance,
getInfoFromNatSpec,
@ -36,10 +37,21 @@ function DeployPanel(): JSX.Element {
error: '',
loading: false,
});
const [teardownState, setTeardownState] = useState({
code: '',
error: '',
loading: false,
});
useEffect(() => {
window.scrollTo(0, document.body.scrollHeight);
}, [deployState, teardownState])
return (
<div className="col-3 d-inline-block">
<h3 className="mb-3">QuickDapp <FormattedMessage id="quickDapp.admin" /></h3>
<h3 className="mb-3" data-id="quick-dapp-admin">QuickDapp <FormattedMessage id="quickDapp.admin" /></h3>
<Button
data-id="resetFunctions"
onClick={() => {
resetInstance();
}}
@ -47,6 +59,7 @@ function DeployPanel(): JSX.Element {
<FormattedMessage id="quickDapp.resetFunctions" />
</Button>
<Button
data-id="deleteDapp"
className="ml-3"
onClick={() => {
emptyInstance();
@ -78,6 +91,7 @@ function DeployPanel(): JSX.Element {
<Form.Group className="mb-2" controlId="formEmail">
<Form.Label className="text-uppercase mb-0"><FormattedMessage id="quickDapp.email" /></Form.Label>
<Form.Control
data-id="surgeEmail"
type="email"
placeholder={intl.formatMessage({ id: 'quickDapp.surgeEmail' })}
required
@ -90,6 +104,7 @@ function DeployPanel(): JSX.Element {
<Form.Group className="mb-2" controlId="formPassword">
<Form.Label className="text-uppercase mb-0"><FormattedMessage id="quickDapp.password" /></Form.Label>
<Form.Control
data-id="surgePassword"
type="password"
placeholder={intl.formatMessage({ id: 'quickDapp.surgePassword' })}
required
@ -104,6 +119,7 @@ function DeployPanel(): JSX.Element {
<InputGroup>
<InputGroup.Text>https://</InputGroup.Text>
<Form.Control
data-id="surgeSubdomain"
type="subdomain"
placeholder={intl.formatMessage({ id: 'quickDapp.uniqueSubdomain' })}
required
@ -133,7 +149,7 @@ function DeployPanel(): JSX.Element {
<br />
<div className="d-inline-flex align-items-center custom-control custom-checkbox">
<input
id="inline-checkbox-1"
id="shareToTwitter"
className="form-check-input custom-control-input"
type="checkbox"
name="group1"
@ -145,7 +161,7 @@ function DeployPanel(): JSX.Element {
/>
<label
htmlFor="inline-checkbox-1"
htmlFor="shareToTwitter"
className="m-0 form-check-label custom-control-label"
style={{ paddingTop: 1 }}
>
@ -154,7 +170,7 @@ function DeployPanel(): JSX.Element {
</div>
<div className="d-inline-flex align-items-center custom-control custom-checkbox ml-3">
<input
id="inline-checkbox-2"
id="shareToFacebook"
className="form-check-input custom-control-input"
type="checkbox"
name="group1"
@ -166,7 +182,7 @@ function DeployPanel(): JSX.Element {
/>
<label
htmlFor="inline-checkbox-2"
htmlFor="shareToFacebook"
className="m-0 form-check-label custom-control-label"
style={{ paddingTop: 1 }}
>
@ -180,8 +196,8 @@ function DeployPanel(): JSX.Element {
</Form.Label>
<br />
<span
data-id="remix_ai_switch"
id="remix_ai_switch"
data-id="useNatSpec"
id="useNatSpec"
className="btn ai-switch pl-0 py-0"
onClick={async () => {
getInfoFromNatSpec(!natSpec.checked);
@ -207,7 +223,7 @@ function DeployPanel(): JSX.Element {
</Form.Label>
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input
id="inline-checkbox-3"
id="verifiedByEtherscan"
className="form-check-input custom-control-input"
type="checkbox"
onChange={(e) => {
@ -220,7 +236,7 @@ function DeployPanel(): JSX.Element {
/>
<label
htmlFor="inline-checkbox-3"
htmlFor="verifiedByEtherscan"
className="m-0 form-check-label custom-control-label"
style={{ paddingTop: 1 }}
>
@ -234,7 +250,7 @@ function DeployPanel(): JSX.Element {
</Form.Label>
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input
id="inline-checkbox-4"
id="noTerminal"
className="form-check-input custom-control-input"
type="checkbox"
onChange={(e) => {
@ -247,7 +263,7 @@ function DeployPanel(): JSX.Element {
/>
<label
htmlFor="inline-checkbox-4"
htmlFor="noTerminal"
className="m-0 form-check-label custom-control-label"
style={{ paddingTop: 1 }}
>
@ -257,6 +273,7 @@ function DeployPanel(): JSX.Element {
</Form.Group>
<ThemeUI />
<Button
data-id="deployDapp"
variant="primary"
type="submit"
className="mt-3"
@ -267,21 +284,51 @@ function DeployPanel(): JSX.Element {
)}
<FormattedMessage id="quickDapp.deploy" />
</Button>
<Button
data-id="teardownDapp"
variant="primary"
className="mt-3 ml-3"
disabled={!formVal.email || !formVal.password || !formVal.subdomain}
// hide this button for now, just for e2e use
style={{ display: 'none' }}
onClick={() => {
setTeardownState({ code: '', error: '', loading: true });
teardown(formVal, (state) => {
setTeardownState({ ...state, loading: false });
})
}}
>
{teardownState.loading && (
<i className="fas fa-spinner fa-spin mr-1"></i>
)}
<FormattedMessage id="quickDapp.teardown" />
</Button>
{deployState.code === 'SUCCESS' && (
<Alert variant="success" className="mt-4">
<Alert variant="success" className="mt-4" data-id="deploySuccess">
<FormattedMessage id="quickDapp.text4" /> <br /> <FormattedMessage id="quickDapp.text5" />
<br />
<a
data-id="dappUrl"
target="_blank"
href={`https://${formVal.subdomain}.surge.sh`}
>{`https://${formVal.subdomain}.surge.sh`}</a>
</Alert>
)}
{deployState.error && (
<Alert variant="danger" className="mt-4">
<Alert variant="danger" className="mt-4" data-id="deployFail">
{deployState.error}
</Alert>
)}
{teardownState.code === 'SUCCESS' && (
<Alert variant="success" className="mt-4" data-id="teardownSuccess">
<FormattedMessage id="quickDapp.text6" />
</Alert>
)}
{teardownState.error && (
<Alert variant="danger" className="mt-4" data-id="teardownFail">
{teardownState.error}
</Alert>
)}
</Form>
</div>
);

@ -56,6 +56,8 @@ const CustomToggle = React.forwardRef(
e.preventDefault();
onClick(e);
}}
id="dropdown-custom-components"
data-id="selectThemesOptions"
className={className.replace('dropdown-toggle', '')}
>
<div className="d-flex">
@ -126,7 +128,6 @@ export function ThemeUI() {
<Dropdown className="w-100">
<Dropdown.Toggle
as={CustomToggle}
id="dropdown-custom-components"
className="btn btn-light btn-block w-100 d-inline-block border border-dark form-control"
icon={''}
>

@ -17,6 +17,7 @@ function EditInstance(): JSX.Element {
<div className="col-9 pl-0">
<div className="my-2 p-3 bg-light">
<input
data-id="dappTitle"
className="form-control"
placeholder={intl.formatMessage({ id: 'quickDapp.dappTitle' })}
value={title}
@ -36,6 +37,7 @@ function EditInstance(): JSX.Element {
</div>
<div className="my-2 p-3 bg-light">
<textarea
data-id="dappInstructions"
className="form-control"
placeholder={intl.formatMessage({ id: 'quickDapp.dappInstructions' })}
value={details}

@ -30,7 +30,7 @@ const ImageUpload = () => {
return (
<div className="col-3 pr-0">
<input className="d-none" type="file" accept="image/*" onChange={handleImageChange} id="upload-button" />
<input data-id="uploadLogo" className="d-none" type="file" accept="image/*" onChange={handleImageChange} id="upload-button" />
<CustomTooltip
placement="right"
tooltipText={intl.formatMessage({ id: 'quickDapp.uploadLogoTooltip' })}

@ -51,15 +51,15 @@ export const Container = forwardRef<HTMLDivElement, Props>(
>
{label}
<div className={`d-flex container-actions`}>
<Remove onClick={onRemove} />
<Handle {...handleProps} />
<Remove onClick={onRemove} data-id={`remove${label.replace(/\s*/g,"")}`} />
<Handle {...handleProps} data-id={`handle${label.replace(/\s*/g,"")}`} />
</div>
</div>
) : null}
{placeholder ? (
children
) : (
<ul className="p-0 m-0 list-unstyled" style={{ overflowY: 'auto' }}>
<ul className="p-0 m-0 list-unstyled" style={{ overflowY: 'auto' }} data-id={`container${label.replace(/\s*/g,"")}`}>
{children}
</ul>
)}

@ -20,6 +20,7 @@ export interface Props {
wrapperStyle?: React.CSSProperties;
children: React.ReactNode;
onRemove?(): void;
id?: any;
}
export const Item = React.memo(
@ -42,6 +43,7 @@ export const Item = React.memo(
transform,
children,
wrapperStyle,
id,
...props
},
ref
@ -93,9 +95,10 @@ export const Item = React.memo(
>
<div className="border-dark bg-light d-flex">
{children}
<Handle {...handleProps} {...listeners} />
<Handle {...handleProps} {...listeners} data-id={`handle${id}`} />
</div>
<button
data-id={`remove${id}`}
className={`d-flex justify-content-center align-items-center position-absolute border-0 rounded-circle item-remove`}
onClick={onRemove}
>

@ -508,6 +508,7 @@ export function MultipleContainers({
function renderSortableItemDragOverlay(id: UniqueIdentifier) {
return (
<Item
id={id}
handle={handle}
style={getItemStyles({
containerId: findContainer(id) as UniqueIdentifier,
@ -521,7 +522,7 @@ export function MultipleContainers({
wrapperStyle={wrapperStyle({ index: 0 })}
dragOverlay
>
<ContractGUI funcABI={abi[id]} />
<ContractGUI funcABI={abi[id]} funcId={id} />
</Item>
);
}
@ -532,6 +533,7 @@ export function MultipleContainers({
{items[containerId].map((item, index) => (
<Item
key={item}
id={item}
handle={handle}
style={getItemStyles({
containerId,
@ -544,7 +546,7 @@ export function MultipleContainers({
})}
wrapperStyle={wrapperStyle({ index })}
>
<ContractGUI funcABI={abi[item]} />
<ContractGUI funcABI={abi[item]} funcId={item} />
</Item>
))}
</Container>
@ -626,6 +628,7 @@ function SortableItem({
return (
<Item
id={id}
ref={disabled ? undefined : setNodeRef}
dragging={isDragging}
sorting={isSorting}
@ -647,7 +650,7 @@ function SortableItem({
listeners={listeners}
onRemove={onRemove}
>
<ContractGUI funcABI={abi[id]} />
<ContractGUI funcABI={abi[id]} funcId={id} />
</Item>
);
}

@ -28,8 +28,10 @@
"quickDapp.no": "No",
"quickDapp.themes": "Themes",
"quickDapp.deploy": "Deploy",
"quickDapp.teardown": "Teardown",
"quickDapp.text4": "Deployed successfully!",
"quickDapp.text5": "Click the link below to view your dapp",
"quickDapp.text6": "Teardown successfully!",
"quickDapp.uploadLogoTooltip": "Click here to change logo",
"quickDapp.dappTitle": "Dapp Title",
"quickDapp.dappInstructions": "Dapp Instructions",

@ -300,6 +300,7 @@ export function UniversalDappUI(props: UdappProps) {
{props.exEnvironment && props.exEnvironment.startsWith('injected') && (
<CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappEditTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextEdit" />}>
<i
data-id="instanceEditIcon"
className="fas fa-edit pr-3"
onClick={() => {
props.editInstance(props.instance)

Loading…
Cancel
Save