Skip to content

Commit

Permalink
[explorer] Implements 'Static' Mode and Tests for Transaction Results (
Browse files Browse the repository at this point in the history
…MystenLabs#1883)

* Re-implements UI tests for Transaction Results. 
* Enables manually varying static transaction data to see effect on UI. In this example  can see what Failure looks like.
* Re-instigates the passing of state when searching for a transaction
* Removes redundant smart contract placeholder code
* Removes redundant yarn packages
  • Loading branch information
apburnie authored May 11, 2022
1 parent 0a315ed commit 5835515
Show file tree
Hide file tree
Showing 18 changed files with 552 additions and 547 deletions.
4 changes: 0 additions & 4 deletions explorer/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"autoprefixer": "^10.4.2",
"concurrently": "^7.0.0",
"eslint-config-prettier": "^8.3.0",
"jest-puppeteer": "^6.1.0",
"onchange": "^7.1.0",
Expand All @@ -29,14 +28,11 @@
"typescript": "^4.5.5"
},
"dependencies": {
"ace-builds": "^1.4.14",
"classnames": "^2.3.1",
"react": "^17.0.2",
"react-ace": "^9.5.0",
"react-dom": "^17.0.2",
"react-router-dom": "^6.2.1",
"@mysten/sui.js": "file:../../sdk/typescript",
"swr": "^1.2.2",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
174 changes: 43 additions & 131 deletions explorer/client/src/__tests__/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,96 +102,9 @@ describe('End-to-end Tests', () => {
});
});

// TODO - rewrite this test to use the new transaction data and state object
/*
describe('Transaction Results', () => {
//Specific to transaction tests:
const successTransactionID = 'txCreateSuccess';
const failTransactionID = 'txFails';
const pendingTransactionID = 'txSendPending';
const missingDataTransactionID = 'txMissingData';
const checkStatus = async (
page: any,
expected: 'success' | 'pending' | 'fail'
) => {
const actual = await page.$eval(
'#transactionStatus',
(el: any) => el.textContent
);
expect(actual).toBe(expected);
};
it('can be searched', async () => {
await page.goto(BASE_URL);
await searchText(page, successTransactionID);
const el = await page.$('#transactionID');
const value = await page.evaluate((el: any) => el.textContent, el);
expect(value.trim()).toBe(successTransactionID);
});
it('can be reached through URL', async () => {
await page.goto(BASE_URL);
await page.goto(`${BASE_URL}/transactions/${successTransactionID}`);
const el = await page.$('#transactionID');
const value = await page.evaluate((el: any) => el.textContent, el);
expect(value.trim()).toBe(successTransactionID);
});
it('has correct structure', async () => {
await page.goto(`${BASE_URL}/transactions/${successTransactionID}`);
const labels = [
'Transaction ID',
'Status',
'From',
'Event',
'Object',
'To',
];
for (let i = 1; i <= labels.length; i++) {
const value = await page.$eval(
`div#textResults > div:nth-child(${i}) > div:nth-child(1)`,
(el: any) => el.textContent
);
expect(value.trim()).toBe(labels[i - 1]);
}
});
it('can be a success', async () => {
await page.goto(`${BASE_URL}/transactions/${successTransactionID}`);
await checkStatus(page, 'success');
});
it('can be pending', async () => {
await page.goto(`${BASE_URL}/transactions/${pendingTransactionID}`);
await checkStatus(page, 'pending');
});
it('can fail', async () => {
await page.goto(`${BASE_URL}/transactions/${failTransactionID}`);
await checkStatus(page, 'fail');
});
it('can have missing data', async () => {
await page.goto(
`${BASE_URL}/transactions/${missingDataTransactionID}`
);
await expectErrorResult(page);
});
});
*/
describe('Object Results', () => {
const successObjectID = 'CollectionObject';
const problemObjectID = 'ProblemObject';
const readOnlyObject = 'ComponentObject';
const notReadOnlyObject = 'CollectionObject';

const checkStatus = async (page: any, expected: 'True' | 'False') => {
const actual = await page.$eval(
'#readOnlyStatus',
(el: any) => el.textContent
);
expect(actual).toBe(expected);
};

it('can be searched', async () => {
await page.goto(BASE_URL);
Expand All @@ -208,34 +121,7 @@ describe('End-to-end Tests', () => {
const value = await page.evaluate((el: any) => el.textContent, el);
expect(value.trim()).toBe(successObjectID);
});
it('has correct structure', async () => {
await page.goto(`${BASE_URL}/objects/${successObjectID}`);

const labels = [
'Object ID',
'Version',
'Read Only?',
'Type',
'Owner',
];

for (let i = 1; i <= labels.length; i++) {
const value = await page.$eval(
`div#descriptionResults > div:nth-child(${i}) > div:nth-child(1)`,
(el: any) => el.textContent
);
expect(value.trim()).toBe(labels[i - 1]);
}
});
it('can be read only', async () => {
await page.goto(`${BASE_URL}/objects/${readOnlyObject}`);
await checkStatus(page, 'True');
});

it('can be not read only', async () => {
await page.goto(`${BASE_URL}/objects/${notReadOnlyObject}`);
await checkStatus(page, 'False');
});
it('can have missing data', async () => {
await page.goto(`${BASE_URL}/objects/${problemObjectID}`);
await expectErrorResult(page);
Expand All @@ -259,25 +145,51 @@ describe('End-to-end Tests', () => {
const value = await page.evaluate((el: any) => el.textContent, el);
expect(value.trim()).toBe(successAddressID);
});
it('has correct structure', async () => {
await page.goto(`${BASE_URL}/addresses/${successAddressID}`);

const labels = ['Address', 'Owned Objects'];

for (let i = 1; i <= labels.length; i++) {
const value = await page.$eval(
`div#textResults > div:nth-child(${i}) > div:nth-child(1)`,
(el: any) => el.textContent
);
expect(value.trim()).toBe(labels[i - 1]);
}
});
it('displays error when no objects', async () => {
await page.goto(`${BASE_URL}/objects/${noObjectsAddressID}`);
await expectErrorResult(page);
});
});
describe('Enables clicking links to', () => {

describe('Transaction Results', () => {
const successID = 'Da4vHc9IwbvOYblE8LnrVsqXwryt2Kmms+xnJ7Zx5E4=';
it('can be searched', async () => {
await page.goto(BASE_URL);
await searchText(page, successID);
const el = await page.$('#transactionID');
const value = await page.evaluate((el: any) => el.textContent, el);
expect(value.trim()).toBe(successID);
});

it('can be reached through URL', async () => {
await page.goto(`${BASE_URL}/transactions/${successID}`);
const el = await page.$('#transactionID');
const value = await page.evaluate((el: any) => el.textContent, el);
expect(value.trim()).toBe(successID);
});
it('can go to object and back', async () => {
const objectID = '7bc832ec31709638cd8d9323e90edf332gff4389';
await page.goto(`${BASE_URL}/transactions/${successID}`);

//Go to Object
const objectLink = await page.$(
'div#txview > div:nth-child(4) > div:nth-child(2)'
);
await objectLink.click();
const el = await page.$('#objectID');
const value = await page.evaluate((x: any) => x.textContent, el);
expect(value.trim()).toBe(objectID);

//Go back to Transaction
const lastTransactionLink = await page.$('#lasttxID > a');
await lastTransactionLink.click();
const el2 = await page.$('#transactionID');
const value2 = await page.evaluate((x: any) => x.textContent, el2);
expect(value2.trim()).toBe(successID);
});
});

describe('Owned Objects have links that enable', () => {
const navigationTemplate = async (
page: any,
parentValue: string,
Expand Down Expand Up @@ -315,7 +227,7 @@ describe('End-to-end Tests', () => {
);
expect(parentText.trim()).toBe(parentValue);
};
it('go from address to object and back', async () => {
it('going from address to object and back', async () => {
await navigationTemplate(
page,
'receiverAddress',
Expand All @@ -324,10 +236,10 @@ describe('End-to-end Tests', () => {
1
);
});
it('go from object to child object and back', async () => {
it('going from object to child object and back', async () => {
await navigationTemplate(page, 'player2', 'objects', 'Image1', 1);
});
it('go from parent to broken image object and back', async () => {
it('going from parent to broken image object and back', async () => {
const parentValue = 'ObjectWBrokenChild';
await page.goto(`${BASE_URL}/objects/${parentValue}`);

Expand Down
93 changes: 25 additions & 68 deletions explorer/client/src/components/displaybox/DisplayBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,7 @@ import { processDisplayValue } from '../../utils/stringUtils';

import styles from './DisplayBox.module.css';

//TO DO - display smart contract info; see mock_data.json for example smart contract data
//import 'ace-builds/src-noconflict/theme-github';
//import AceEditor from 'react-ace';

function SmartContractBox({
display,
}: {
display: string | { bytes: number[] };
}) {
return (
<div className={styles.imagebox}>
Displaying Smart Contracts Not yet Supported
</div>
);
/*
return (
<div className={styles['display-container']}>
<AceEditor
theme="github"
value={data.data.contents.display?.data}
showGutter={true}
readOnly={true}
fontSize="0.8rem"
className={styles.codebox}
/>
</div>
);
*/
}

function DisplayBox({
display,
tag,
}: {
display: string | { bytes: number[] };
tag: 'imageURL' | 'moveScript';
}) {
function DisplayBox({ display }: { display: string | { bytes: number[] } }) {
const [hasDisplayLoaded, setHasDisplayLoaded] = useState(false);
const [hasFailedToLoad, setHasFailedToLoad] = useState(false);

Expand All @@ -66,37 +30,30 @@ function DisplayBox({
[setHasFailedToLoad]
);

if (tag === 'moveScript') {
return <SmartContractBox display={display} />;
}

if (tag === 'imageURL') {
return (
<div className={styles['display-container']}>
{!hasDisplayLoaded && (
<div className={styles.imagebox} id="pleaseWaitImage">
Please wait for display to load
</div>
)}
{hasFailedToLoad ? (
<div className={styles.imagebox} id="noImage">
No Image was Found
</div>
) : (
<img
id="loadedImage"
className={styles.imagebox}
style={imageStyle}
alt="NFT"
src={processDisplayValue(display)}
onLoad={handleImageLoad}
onError={handleImageFail}
/>
)}
</div>
);
}
return <div />;
return (
<div className={styles['display-container']}>
{!hasDisplayLoaded && (
<div className={styles.imagebox} id="pleaseWaitImage">
Please wait for display to load
</div>
)}
{hasFailedToLoad ? (
<div className={styles.imagebox} id="noImage">
No Image was Found
</div>
) : (
<img
id="loadedImage"
className={styles.imagebox}
style={imageStyle}
alt="NFT"
src={processDisplayValue(display)}
onLoad={handleImageLoad}
onError={handleImageFail}
/>
)}
</div>
);
}

export default DisplayBox;
23 changes: 4 additions & 19 deletions explorer/client/src/components/ownedobjects/OwnedObjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React, { useCallback, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

import { DefaultRpcClient as rpc } from '../../utils/api/DefaultRpcClient';
import { IS_STATIC_ENV } from '../../utils/envUtil';
import { parseImageURL, parseObjectType } from '../../utils/objectUtils';
import { navigateWithUnknown } from '../../utils/searchUtil';
import {
Expand Down Expand Up @@ -41,13 +42,8 @@ const IS_COIN_TYPE = (typeDesc: string): boolean => /::Coin::/.test(typeDesc);
const lastRowHas2Elements = (itemList: any[]): boolean =>
itemList.length % 3 === 2;

function OwnedObject({ id }: { id: string }) {
if (process.env.REACT_APP_DATA === 'static') {
return <OwnedObjectStatic id={id} />;
} else {
return <OwnedObjectAPI id={id} />;
}
}
const OwnedObject = ({ id }: { id: string }) =>
IS_STATIC_ENV ? <OwnedObjectStatic id={id} /> : <OwnedObjectAPI id={id} />;

function OwnedObjectStatic({ id }: { id: string }) {
const objects = findOwnedObjectsfromID(id);
Expand Down Expand Up @@ -357,18 +353,7 @@ function OwnedObjectView({ results }: { results: resultType }) {
>
{entryObj.display !== undefined && (
<div className={styles.previewimage}>
<DisplayBox
display={entryObj.display}
// TODO: clean this logic
tag={
typeof entryObj.display === 'object' &&
'category' in entryObj.display &&
entryObj.display['category'] ===
'moveScript'
? 'moveScript'
: 'imageURL'
}
/>
<DisplayBox display={entryObj.display} />
</div>
)}
{Object.entries(entryObj).map(([key, value], index2) => (
Expand Down
Loading

0 comments on commit 5835515

Please sign in to comment.