Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add testing instructions and auto tests #1

Open
wants to merge 15 commits into
base: production
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ delete.bat
model/build/Mask*
model/build/taco*
tags
frontend/yarn.lock
2 changes: 1 addition & 1 deletion frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Dockerfile for trash-ai frontend

# Stage 1: Build the project
FROM node:16.12.0 as builder
FROM node:16.20.0 as builder

# Set the working directory
WORKDIR /app
Expand Down
5 changes: 5 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@ yarn build
yarn lint
```

### Run Cypress Tests
```
yarn run cypress open
```

### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
62 changes: 62 additions & 0 deletions frontend/__tests__/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Tests and Verifications

## Automatic Tests

### Scenarios
1. Does the landing pag load?
2. On hitting show samples, does processing complete in an expected amount of time? Does it show all the results expected?
3. After recieving results, can you click an image and does the page show the expected data/metadata/etc?
4. After recieving results, does the summary page contain the correct data?

## How to run

1. Navigate to `frontend/`
2. Run `yarn install`
2. Spin up docker container
`docker-compose up`
3. Run the auto tests
`yarn run jest`

## Manual Tests

1. Does the landing pag load?

When you open the landing page. Either at https://www.trashai.org/ or http://localhost:5150

The page should loads in a reasonable timeframe. (<2 seconds)

*You can use the `Network` tab in the dev tools for more fine grained analysis.*

2. On hitting show samples, does processing complete in an expected amount of time? Does it show all the results expected?

When the show samples button is pressed. (as depicted below)
![Instructions](misc/Show_Samples_Button.png "Show Title Button")

Then the app will start processing images. (as depcited below)
![Processing](misc/Processing_Samples.png "Processing Samples Progress Bar")

*The processing should be relatively quick, it it takes more than a minute, something is definetly wrong.*

When the processing is done, the results will be available in the summary page.

![Summary ](misc/Summary_Of_Samples.png "Summary of Sample Results")

It should be populated like above.

3. After recieving results, can you click an image and does the page show the expected data/metadata/etc?

When one of the links in the summary table is clicked.

![Open images](misc/Open_images.png "Open Images")

Then the images will be displayed along with the segmentation and classes detected.

![List Images](misc/Images_with_Segmentation.png "List Images")

When the METADATA tab is opened, the relevant metadata for the image is displayed.

![View Metadata](misc/Viewing_Metadata.png "View Metadata")

4. After recieving results, does the summary page contain the correct data?

*The summary page shows the results of processing a random sample of images, as long as it's not empty it can be considered as correct.*
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/__tests__/misc/Open_images.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/__tests__/misc/Processing_Samples.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/__tests__/misc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*placeholder*
Binary file added frontend/__tests__/misc/Show_Samples_Button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/__tests__/misc/Summary_Of_Samples.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/__tests__/misc/Viewing_Metadata.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 110 additions & 0 deletions frontend/__tests__/smokeTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/* eslint-disable no-undef */
const timeout = 12000
const url = 'http://localhost:5150/'

describe(
'Smoke test for Trash-AI',
() => {
let page
beforeAll(async () => {
page = await global.__BROWSER__.newPage()
await page.setViewport({
width: 1536,
height: 960,
})
await page.goto(url)
}, timeout)

afterAll(async () => {
await page.close()
})

it('should load without error', async () => {
const text = await page.evaluate(() => document.body.textContent)
expect(text).toContain('Trash AI')
})

it(
'should show samples when prompted',
async () => {
// Open actions menu
const openActionsBtn = await page.waitForSelector(
'#actions-button-test-id',
)
await openActionsBtn.click()
await page.waitForTimeout(1000)

// Click Show Samples
const showSamplesBtn = await page.waitForSelector(
'#show-samples-test-id',
)
await showSamplesBtn.click()
await page.waitForTimeout(2000)

// Navigate to Summary page
const summaryBtn = await page.waitForSelector(
'#summary-tab-test-id',
)
await summaryBtn.click()
await page.waitForTimeout(500)

// Check if navigations was successful
current_url = await page.url()
expect(current_url).toBe(`${url}summary/detections`)

// Check if results are displayed
const drinkCanImg = await page.waitForSelector(
'a[href="/detection/Drink%20can"]',
)
await drinkCanImg.click()
await page.waitForTimeout(500)

// Check if navigation happened
current_url = await page.url()
expect(current_url).toBe(`${url}detection/Drink%20can`)

// Navigate to image view page
const sampleImg = await page.waitForSelector(
'div[id="sample01.jpg-test-id"]',
)
await sampleImg.click()
await page.waitForTimeout(500)

// Check if navigation happened
current_url = await page.url()
expect(current_url).toBe(`${url}image/0/image`)

// Check if the image is loaded
const canvasImg = await page.waitForSelector('#canvasparent')

// Check of the images classes are loaded
const drinkCanClass = await page.waitForSelector(
'a[href="/detection/Drink%20can"]',
)

const paperCupClass = await page.waitForSelector(
'a[href="/detection/Paper%20cup"]',
)

// Check of the image and metadata tabs are loaded
const imageTab = await page.waitForSelector(
'#image-tab-test-id',
)

const metadataTab = await page.waitForSelector(
'#meta-tab-test-id',
)
metadataTab.click()
await page.waitForTimeout(500)

// Check is exif data is displayed
const exifData = await page.waitForSelector('#exifData-test-id')
// Check if metadata is displayed
const metaData = await page.waitForSelector('#metaData-test-id')
await page.waitForTimeout(500)
},
timeout,
)
},
timeout,
)
8 changes: 8 additions & 0 deletions frontend/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineConfig } from "cypress";

export default defineConfig({
e2e: {
baseUrl: "https://www.trashai.org/",
pageLoadTimeout: 3000
},
});
5 changes: 5 additions & 0 deletions frontend/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
globalSetup: './setup.js',
globalTeardown: './teardown.js',
testEnvironment: './puppeteer_environment.js',
}
7 changes: 6 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"serve": "vite preview",
"build": "vite build",
"lint": "vue-cli-service lint",
"dev": "vite"
"dev": "vite",
"test": "jest"
},
"dependencies": {
"@fawmi/vue-google-maps": "^0.9.72",
Expand All @@ -23,11 +24,14 @@
"dexie": "^3.2.2",
"file-saver": "^2.0.5",
"fuse.js": "^6.6.2",
"jest": "^29.5.0",
"jszip": "^3.10.0",
"loglevel": "^1.8.0",
"p-queue": "^7.3.0",
"pinia": "^2.0.17",
"pinia-plugin-persistedstate": "^1.6.3",
"puppeteer": "^20.7.1",
"rimraf": "^5.0.1",
"roboto-fontface": "^0.10.0",
"rxjs": "^7.5.7",
"ts-exif-parser": "^0.2.2",
Expand Down Expand Up @@ -56,6 +60,7 @@
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.2.0",
"jest-puppeteer": "^9.0.0",
"prettier": "^2.7.1",
"sass": "^1.53.0",
"typescript": "^4.7.4",
Expand Down
36 changes: 36 additions & 0 deletions frontend/puppeteer_environment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import NodeEnvironment from 'jest-environment-node'
import puppeteer from 'puppeteer'
import fs from 'fs'
import os from 'os'
import path from 'path'

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup')

class PuppeteerEnvironment extends NodeEnvironment {
constructor(config) {
super(config)
}

async setup() {
console.log('Setup Test Environment.')
await super.setup()
const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf8')
if (!wsEndpoint) {
throw new Error('wsEndpoint not found')
}
this.global.__BROWSER__ = await puppeteer.connect({
browserWSEndpoint: wsEndpoint,
})
}

async teardown() {
console.log('Teardown Test Environment.')
await super.teardown()
}

runScript(script) {
return super.runScript(script)
}
}

module.exports = PuppeteerEnvironment
23 changes: 23 additions & 0 deletions frontend/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import puppeteer from 'puppeteer'
import fs from 'fs'
import mkdirp from 'mkdirp'
import os from 'os'
import path from 'path'

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup')

module.exports = async function () {
console.log('Setup Puppeteer')
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
args: ['--window-size=1920,1080'],
})
// This global is not available inside tests but only in global teardown
global.__BROWSER_GLOBAL__ = browser
// Instead, we expose the connection details via file system to be used in tests
mkdirp.sync(DIR)

console.log(`DIR ${DIR}`)
fs.writeFileSync(path.join(DIR, 'wsEndpoint'), browser.wsEndpoint())
}
6 changes: 4 additions & 2 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<v-app-bar-nav-icon
v-if="is_mobile"
variant="text"
id="menu-button-test-id"
@click.stop="drawer = !drawer"
/>

Expand Down Expand Up @@ -98,12 +99,13 @@
@click="$router.push({ name: 'about' })"
:active="isactive('about')"
>
<v-list-item-title>
<v-list-item-title id="about-tab-test-id">
<v-icon class="mr-4">mdi-information</v-icon>
<span>About</span>
</v-list-item-title>
</v-list-item>
<v-list-item
id="uploads-tab-test-id"
@click="
$router.push({
name: 'uploads',
Expand All @@ -126,7 +128,7 @@
"
:active="isactive('summary')"
>
<v-list-item-title>
<v-list-item-title id="summary-tab-test-id">
<v-icon class="mr-4">
mdi-book-open-variant
</v-icon>
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/components/model/thumb.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<!-- eslint-disable prettier/prettier -->
<template>
<div class="mx-0 border">
<div class="ml-3">
<div
class="mx-0 border"
>
<div class="ml-3" :id="item.filename + '-test-id'">
<b>{{ item.filename }}</b>
</div>
<v-divider
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/components/upload_control.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<template v-slot:activator="menu">
<v-btn
color="primary"
id="actions-button-test-id"
v-bind="menu.props"
block
>
Expand All @@ -26,13 +27,15 @@
<v-card>
<div
class="d-flex justify-space-between menu-btn-a"
id="upload-samples-test-id"
@click="form.click()"
>
<v-icon class="justify-start"> mdi-upload </v-icon>
<span class="justify-end">Upload</span>
</div>
<div
class="d-flex justify-space-between menu-btn-b"
id="show-samples-test-id"
v-if="!store.hash_ids.length > 0"
@click="store.do_sampleupload"
>
Expand All @@ -41,6 +44,7 @@
</div>
<div
class="d-flex justify-space-between menu-btn-a"
id="download-samples-test-id"
v-if="store.hash_ids.length > 0"
@click="store.download_all"
>
Expand All @@ -51,6 +55,7 @@
</div>
<div
class="d-flex justify-space-between menu-btn-d"
id="clear-samples-test-id"
v-if="store.hash_ids.length > 0"
@click="store.clear"
>
Expand Down
Loading