diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..cc37a36d --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +CYPRESS_AWS_IDENTITY_POOL_ID="XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab" +CYPRESS_AWS_AUTH_REGION="XX-XXXX-X" +CYPRESS_AWS_USER_POOL_ID="XX-XXXX-X_12ab34cd9" +CYPRESS_AWS_USER_POOL_WEB_CLIENT_ID="26-char alphanumeric string" +CYPRESS_AWS_MANDATORY_SIGN_IN=TRUE +CYPRESS_AWS_AUTHENTICATION_FLOW_TYPE="XXX_XXXX_XXX" +CYPRESS_AWS_STORAGE_BUCKET="XX-XXXXX" +CYPRESS_AWS_STORAGE_REGION="XX-XXXX-X" +CYPRESS_COGNITO_USER_NAME="abc@abc.com" +CYPRESS_COGNITO_USER_PASS="abc123" +CYPRESS_COGNITO_USER_PASS_LENGTH="0" +CYPRESS_COGNITO_USER_PASS_REQUIRE_LOWERCASE=TRUE +CYPRESS_COGNITO_USER_PASS_REQUIRE_UPPERCASE=TRUE +CYPRESS_COGNITO_USER_PASS_REQUIRE_NUMBER=TRUE +CYPRESS_COGNITO_USER_PASS_REQUIRE_SYMBOL=TRUE diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 46769fa6..00000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -cypress/integration/* -cypress/utils/* \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..c791b67a --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "parser": "babel-eslint", + "plugins": ["cypress", "react"] +} diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 67231808..d883b8f2 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -6,4 +6,14 @@ labels: enhancement assignees: "" --- -It would be cool if the UDT could ... +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 566140bc..1b7ce94d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: with: node-version: 12 - name: Run Prettier Test - run: npx prettier --check "src/**/*.js" + run: npx prettier --check . - name: Run Lint Test run: | # TODO this takes 1-2 mins to install, run eslint w/o installing @@ -38,3 +38,18 @@ jobs: record: true env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + CYPRESS_AWS_IDENTITY_POOL_ID: ${{ secrets.CYPRESS_AWS_IDENTITY_POOL_ID }} + CYPRESS_AWS_AUTH_REGION: ${{ secrets.CYPRESS_AWS_AUTH_REGION }} + CYPRESS_AWS_USER_POOL_ID: ${{ secrets.CYPRESS_AWS_USER_POOL_ID }} + CYPRESS_AWS_USER_POOL_WEB_CLIENT_ID: ${{ secrets.CYPRESS_AWS_USER_POOL_WEB_CLIENT_ID }} + CYPRESS_AWS_MANDATORY_SIGN_IN: ${{ secrets.CYPRESS_AWS_MANDATORY_SIGN_IN }} + CYPRESS_AWS_AUTHENTICATION_FLOW_TYPE: ${{ secrets.CYPRESS_AWS_AUTHENTICATION_FLOW_TYPE }} + CYPRESS_AWS_STORAGE_BUCKET: ${{ secrets.CYPRESS_AWS_STORAGE_BUCKET }} + CYPRESS_AWS_STORAGE_REGION: ${{ secrets.CYPRESS_AWS_STORAGE_REGION }} + CYPRESS_COGNITO_USER_NAME: ${{ secrets.CYPRESS_COGNITO_USER_NAME }} + CYPRESS_COGNITO_USER_PASS: ${{ secrets.CYPRESS_COGNITO_USER_PASS }} + CYPRESS_COGNITO_USER_PASS_LENGTH: ${{ secrets.CYPRESS_COGNITO_USER_PASS_LENGTH }} + CYPRESS_COGNITO_USER_PASS_REQUIRE_LOWERCASE: ${{ secrets.CYPRESS_COGNITO_USER_PASS_REQUIRE_LOWERCASE }} + CYPRESS_COGNITO_USER_PASS_REQUIRE_UPPERCASE: ${{ secrets.CYPRESS_COGNITO_USER_PASS_REQUIRE_UPPERCASE }} + CYPRESS_COGNITO_USER_PASS_REQUIRE_NUMBER: ${{ secrets.CYPRESS_COGNITO_USER_PASS_REQUIRE_NUMBER }} + CYPRESS_COGNITO_USER_PASS_REQUIRE_SYMBOL: ${{ secrets.CYPRESS_COGNITO_USER_PASS_REQUIRE_SYMBOL }} diff --git a/.gitignore b/.gitignore index 6a7a2fd6..509ae4bb 100644 --- a/.gitignore +++ b/.gitignore @@ -31,15 +31,16 @@ dist desktop/node_modules /lib - src/components/WebApp/myAWSconfig.js package-lock.json src/components/WebApp/myAWSconfig.js .env .cache - +logs # eventually we'll commit these cypress/snapshots +cypress/screenshots .idea *.db +.vercel diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..809e6e15 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,13 @@ +.cache +build/* +dist/* +lib/* +logs/* +node_modules/* +.env +.env.example +yarn-error.log +cypress/snapshots/* +cypress/videos/* +cypress/screenshots/* +yarn.lock diff --git a/README.md b/README.md index 01485e1d..fe565aaf 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,9 @@ Try it out at [udt.dev](https://udt.dev), [download the desktop app](https://github.com/UniversalDataTool/universal-data-tool/releases) or [run on-premise](https://docs.universaldatatool.com/running-on-premise). +> [!NOTE] +> If you think Universal Data Tool is cool, check out my new project for [creating electronics with React](https://docs.tscircuit.com) +

@@ -74,7 +77,9 @@ The Universal Data Tool is a web/desktop app for editing and annotating images, ## Sponsors -[![wao.ai sponsorship image](https://s3.amazonaws.com/asset.workaround.online/sponsorship-banner-1.png)](https://wao.ai) +[![wao.ai sponsorship image](https://user-images.githubusercontent.com/1910070/107271376-20fbd100-6a1a-11eb-9f82-2d10607591ba.png)](https://wao.ai) +[![momentum image](https://user-images.githubusercontent.com/1910070/107270943-8bf8d800-6a19-11eb-97c2-895b0280aa8a.png)](https://momentum-tech.ca/) +[![enabled intelligence image](https://user-images.githubusercontent.com/1910070/107271756-aaab9e80-6a1a-11eb-887c-6f5d009f0fd2.png)](https://www.enabledintelligence.net/) ## Installation diff --git a/cypress.json b/cypress.json index bd36abdc..7fb8019b 100644 --- a/cypress.json +++ b/cypress.json @@ -1,4 +1,5 @@ { + "testFiles": ["**/*.spec.js"], "projectId": "w62sqq", "pageLoadTimeout": 60000, "defaultCommandTimeout": 4000, diff --git a/cypress/.gitignore b/cypress/.gitignore index 40943445..4603fda6 100644 --- a/cypress/.gitignore +++ b/cypress/.gitignore @@ -1 +1,4 @@ videos +snapshots +screenshots +.cache diff --git a/cypress/fixtures/assets-dummies/audio.mp3 b/cypress/fixtures/assets-dummies/audio.mp3 new file mode 100644 index 00000000..8fdf3b8d Binary files /dev/null and b/cypress/fixtures/assets-dummies/audio.mp3 differ diff --git a/cypress/fixtures/assets-dummies/image1.jpg b/cypress/fixtures/assets-dummies/image1.jpg new file mode 100644 index 00000000..462c70dc Binary files /dev/null and b/cypress/fixtures/assets-dummies/image1.jpg differ diff --git a/cypress/fixtures/assets-dummies/image2.jpg b/cypress/fixtures/assets-dummies/image2.jpg new file mode 100644 index 00000000..d9b0739f Binary files /dev/null and b/cypress/fixtures/assets-dummies/image2.jpg differ diff --git a/cypress/fixtures/assets-dummies/pdf1.pdf b/cypress/fixtures/assets-dummies/pdf1.pdf new file mode 100644 index 00000000..32a76fef Binary files /dev/null and b/cypress/fixtures/assets-dummies/pdf1.pdf differ diff --git a/cypress/fixtures/assets-dummies/pdf2.pdf b/cypress/fixtures/assets-dummies/pdf2.pdf new file mode 100644 index 00000000..9d8b30df Binary files /dev/null and b/cypress/fixtures/assets-dummies/pdf2.pdf differ diff --git a/cypress/fixtures/assets-dummies/text1.txt b/cypress/fixtures/assets-dummies/text1.txt new file mode 100644 index 00000000..93116513 --- /dev/null +++ b/cypress/fixtures/assets-dummies/text1.txt @@ -0,0 +1 @@ +This has made me so happy. I love this. \ No newline at end of file diff --git a/cypress/fixtures/assets-dummies/text2.txt b/cypress/fixtures/assets-dummies/text2.txt new file mode 100644 index 00000000..773086bc --- /dev/null +++ b/cypress/fixtures/assets-dummies/text2.txt @@ -0,0 +1 @@ +At first I wasn't sure. Then I thought, oh it's not very good. \ No newline at end of file diff --git a/cypress/fixtures/assets-dummies/text3.txt b/cypress/fixtures/assets-dummies/text3.txt new file mode 100644 index 00000000..93116513 --- /dev/null +++ b/cypress/fixtures/assets-dummies/text3.txt @@ -0,0 +1 @@ +This has made me so happy. I love this. \ No newline at end of file diff --git a/cypress/fixtures/assets-dummies/timeSeries.json b/cypress/fixtures/assets-dummies/timeSeries.json new file mode 100644 index 00000000..cb0dfaa3 --- /dev/null +++ b/cypress/fixtures/assets-dummies/timeSeries.json @@ -0,0 +1,7 @@ +{ + "timeData": [ + { "time": 0, "value": 0 }, + { "time": 500, "value": 0.75 }, + { "time": 1000, "value": 1 } + ] +} diff --git a/cypress/fixtures/assets-dummies/video.mp4 b/cypress/fixtures/assets-dummies/video.mp4 new file mode 100644 index 00000000..ed139d6d Binary files /dev/null and b/cypress/fixtures/assets-dummies/video.mp4 differ diff --git a/cypress/fixtures/cat.jpg b/cypress/fixtures/cat.jpg new file mode 100644 index 00000000..c8f889f9 Binary files /dev/null and b/cypress/fixtures/cat.jpg differ diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json deleted file mode 100644 index 02e42543..00000000 --- a/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/cypress/fixtures/samples-dummies/AudioTranscription.json b/cypress/fixtures/samples-dummies/AudioTranscription.json new file mode 100644 index 00000000..042e8be8 --- /dev/null +++ b/cypress/fixtures/samples-dummies/AudioTranscription.json @@ -0,0 +1,13 @@ +{ + "name": "Audio Transcription", + "interface": { + "type": "audio_transcription", + "description": "# Markdown description here" + }, + "samples": [ + { + "_id": "s5tghce7k", + "audioUrl": "https://html5tutorial.info/media/vincent.mp3" + } + ] +} diff --git a/cypress/fixtures/samples-dummies/Composite.json b/cypress/fixtures/samples-dummies/Composite.json new file mode 100644 index 00000000..5cb48db1 --- /dev/null +++ b/cypress/fixtures/samples-dummies/Composite.json @@ -0,0 +1,42 @@ +{ + "name": "Composite", + "interface": { + "type": "composite", + "fields": [ + { + "fieldName": "textInfo", + "interface": { + "type": "data_entry", + "surveyjs": { + "questions": [ + { + "type": "text", + "name": "group_letter", + "title": "Letter of Group" + } + ] + } + } + }, + { + "fieldName": "segmentation", + "interface": { + "type": "image_segmentation", + "labels": ["group text"], + "regionTypesAllowed": ["bounding-box"] + } + } + ] + }, + "description": "# Markdown description here", + "samples": [ + { + "_id": "s2y1li73c", + "imageUrl": "https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image1.jpg" + }, + { + "_id": "snodnb8eb", + "imageUrl": "https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image2.jpg" + } + ] +} diff --git a/cypress/fixtures/samples-dummies/DataEntry.json b/cypress/fixtures/samples-dummies/DataEntry.json new file mode 100644 index 00000000..6082d928 --- /dev/null +++ b/cypress/fixtures/samples-dummies/DataEntry.json @@ -0,0 +1,20 @@ +{ + "name": "Data Entry", + "interface": { + "type": "data_entry", + "description": "# Markdown description here", + "surveyjs": { + "questions": [ + { + "type": "text", + "name": "document_title", + "title": "Title of Document" + } + ] + } + }, + "samples": [ + { "_id": "sj2skbtg3", "pdfUrl": "https://arxiv.org/pdf/1906.01969.pdf" }, + { "_id": "skszdkkb9", "pdfUrl": "https://arxiv.org/pdf/1908.07069.pdf" } + ] +} diff --git a/cypress/fixtures/samples-dummies/Empty.json b/cypress/fixtures/samples-dummies/Empty.json new file mode 100644 index 00000000..3b0c5cd5 --- /dev/null +++ b/cypress/fixtures/samples-dummies/Empty.json @@ -0,0 +1 @@ +{ "name": "Empty", "interface": {}, "samples": [] } diff --git a/cypress/fixtures/samples-dummies/ImageClassification.json b/cypress/fixtures/samples-dummies/ImageClassification.json new file mode 100644 index 00000000..f25c41a9 --- /dev/null +++ b/cypress/fixtures/samples-dummies/ImageClassification.json @@ -0,0 +1,17 @@ +{ + "name": "Image Classification", + "interface": { + "type": "image_classification", + "labels": ["valid", "invalid"] + }, + "samples": [ + { + "_id": "sww95cyio", + "imageUrl": "https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image1.jpg" + }, + { + "_id": "strmmwo1g", + "imageUrl": "https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image2.jpg" + } + ] +} diff --git a/cypress/fixtures/samples-dummies/ImageLandmark.json b/cypress/fixtures/samples-dummies/ImageLandmark.json new file mode 100644 index 00000000..69ad0e82 --- /dev/null +++ b/cypress/fixtures/samples-dummies/ImageLandmark.json @@ -0,0 +1,127 @@ +{ + "name": "Image Landmark", + "interface": { + "type": "image_landmark_annotation", + "keypointDefinitions": { + "human": { + "landmarks": { + "nose": { + "label": "Nose", + "color": "#f00", + "defaultPosition": [0, 0] + }, + "leftEye": { + "label": "Left Eye", + "color": "#00f", + "defaultPosition": [-0.05, -0.05] + }, + "leftEar": { + "label": "Left Ear", + "color": "#0ff", + "defaultPosition": [-0.1, -0.05] + }, + "rightEye": { + "label": "Left Eye", + "color": "#f0f", + "defaultPosition": [0.05, -0.05] + }, + "rightEar": { + "label": "Left Ear", + "color": "#00f", + "defaultPosition": [0.1, -0.05] + }, + "sternum": { + "label": "Sternum", + "color": "#0f0", + "defaultPosition": [0, 0.1] + }, + "leftShoulder": { + "label": "Left Shoulder", + "color": "#0ff", + "defaultPosition": [-0.2, 0.1] + }, + "rightShoulder": { + "label": "Right Shoulder", + "color": "#00f", + "defaultPosition": [0.2, 0.1] + }, + "leftElbow": { + "label": "Left Elbow", + "color": "#0f0", + "defaultPosition": [-0.2, 0.2] + }, + "rightElbow": { + "label": "Right Elbow", + "color": "#f00", + "defaultPosition": [0.2, 0.2] + }, + "leftHand": { + "label": "Left Hand", + "color": "#00f", + "defaultPosition": [-0.2, 0.3] + }, + "rightHand": { + "label": "Right Hand", + "color": "#f0f", + "defaultPosition": [0.2, 0.3] + }, + "leftThigh": { + "label": "Left Thigh", + "color": "#f00", + "defaultPosition": [-0.1, 0.35] + }, + "rightThigh": { + "label": "Right Thigh", + "color": "#0ff", + "defaultPosition": [0.1, 0.35] + }, + "leftKnee": { + "label": "Left Thigh", + "color": "#ff0", + "defaultPosition": [-0.15, 0.45] + }, + "rightKnee": { + "label": "Right Thigh", + "color": "#0f0", + "defaultPosition": [0.15, 0.45] + }, + "leftFoot": { + "label": "Left Foot", + "color": "#00f", + "defaultPosition": [-0.15, 0.55] + }, + "rightFoot": { + "label": "Right Foot", + "color": "#f00", + "defaultPosition": [0.15, 0.55] + } + }, + "connections": [ + ["sternum", "nose"], + ["nose", "leftEye"], + ["leftEye", "leftEar"], + ["nose", "rightEye"], + ["rightEye", "rightEar"], + ["sternum", "leftShoulder"], + ["leftShoulder", "leftElbow"], + ["leftElbow", "leftHand"], + ["sternum", "leftThigh"], + ["leftThigh", "leftKnee"], + ["leftKnee", "leftFoot"], + ["sternum", "rightShoulder"], + ["rightShoulder", "rightElbow"], + ["rightElbow", "rightHand"], + ["sternum", "rightThigh"], + ["rightThigh", "rightKnee"], + ["rightKnee", "rightFoot"] + ] + } + } + }, + "samples": [ + { + "_id": "sdgi7veio", + "imageUrl": "https://media.istockphoto.com/photos/businesswoman-picture-id918002786" + } + ] +} diff --git a/cypress/fixtures/samples-dummies/ImageSegmentation.json b/cypress/fixtures/samples-dummies/ImageSegmentation.json new file mode 100644 index 00000000..4b69340d --- /dev/null +++ b/cypress/fixtures/samples-dummies/ImageSegmentation.json @@ -0,0 +1,18 @@ +{ + "name": "Image Segmentation", + "interface": { + "type": "image_segmentation", + "labels": ["valid", "invalid"], + "regionTypesAllowed": ["bounding-box", "polygon", "point"] + }, + "samples": [ + { + "_id": "srrtsy1dv", + "imageUrl": "https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image1.jpg" + }, + { + "_id": "sq7azli34", + "imageUrl": "https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image2.jpg" + } + ] +} diff --git a/cypress/fixtures/samples-dummies/NamedEntityRecognition.json b/cypress/fixtures/samples-dummies/NamedEntityRecognition.json new file mode 100644 index 00000000..1db7f4e3 --- /dev/null +++ b/cypress/fixtures/samples-dummies/NamedEntityRecognition.json @@ -0,0 +1,25 @@ +{ + "name": "Named Entity Recognition", + "interface": { + "type": "text_entity_recognition", + "overlapAllowed": false, + "labels": [ + { "id": "food", "displayName": "Food", "description": "Edible item." }, + { + "id": "hat", + "displayName": "Hat", + "description": "Something worn on the head." + } + ] + }, + "samples": [ + { + "_id": "sa6l4bt9n", + "document": "This strainer makes a great hat, I'll wear it while I serve spaghetti!" + }, + { + "_id": "s95oxk8n4", + "document": "Why are all these dumpings covered in butter?!" + } + ] +} diff --git a/cypress/fixtures/samples-dummies/NotSupported.json b/cypress/fixtures/samples-dummies/NotSupported.json new file mode 100644 index 00000000..f7da041d --- /dev/null +++ b/cypress/fixtures/samples-dummies/NotSupported.json @@ -0,0 +1,17 @@ +{ + "name": "Not Supported", + "interface": { + "type": "audio_transcription", + "description": "# Markdown description here" + }, + "samples": [ + { + "_id": "sww95cyio", + "imageUrl": "https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image1.jpg" + }, + { + "_id": "sprtlkb6r", + "videoUrl": "https://s3.amazonaws.com/asset.workaround.online/SampleVideo_1280x720_1mb.mp4" + } + ] +} diff --git a/cypress/fixtures/samples-dummies/PixelSegmentation.json b/cypress/fixtures/samples-dummies/PixelSegmentation.json new file mode 100644 index 00000000..66558aa8 --- /dev/null +++ b/cypress/fixtures/samples-dummies/PixelSegmentation.json @@ -0,0 +1,22 @@ +{ + "name": "Pixel Segmentation", + "interface": { + "type": "image_pixel_segmentation", + "labels": ["hair", "mouth", "nose", "eyes"], + "description": "These are AI-generated faces, not real people." + }, + "samples": [ + { + "_id": "s67fjg4xn", + "imageUrl": "https://s3.amazonaws.com/datasets.workaround.online/faces/010041.jpg" + }, + { + "_id": "sya6a14y5", + "imageUrl": "https://s3.amazonaws.com/datasets.workaround.online/faces/010026.jpg" + }, + { + "_id": "s4ldv4ltg", + "imageUrl": "https://s3.amazonaws.com/datasets.workaround.online/faces/010025.jpg" + } + ] +} diff --git a/cypress/fixtures/samples-dummies/TextClassification.json b/cypress/fixtures/samples-dummies/TextClassification.json new file mode 100644 index 00000000..63e3c7b5 --- /dev/null +++ b/cypress/fixtures/samples-dummies/TextClassification.json @@ -0,0 +1,18 @@ +{ + "name": "Text Classification", + "interface": { + "type": "text_classification", + "labels": ["positive_sentiment", "negative_sentiment"] + }, + "samples": [ + { "_id": "slohyn137", "document": "Wow this is terrible. I hated it." }, + { + "_id": "svkw5i7ci", + "document": "This has made me so happy. I love this." + }, + { + "_id": "spsd5ta7s", + "document": "At first I wasn't sure. Then I thought, oh it's not very good." + } + ] +} diff --git a/cypress/fixtures/samples-dummies/TextEntityRelations.json b/cypress/fixtures/samples-dummies/TextEntityRelations.json new file mode 100644 index 00000000..be5f7e09 --- /dev/null +++ b/cypress/fixtures/samples-dummies/TextEntityRelations.json @@ -0,0 +1,25 @@ +{ + "name": "Text Entity Relations", + "interface": { + "type": "text_entity_relations", + "entityLabels": [ + { "id": "food", "displayName": "Food", "description": "Edible item." }, + { + "id": "hat", + "displayName": "Hat", + "description": "Something worn on the head." + } + ], + "relationLabels": [{ "id": "subject", "displayName": "Subject" }] + }, + "samples": [ + { + "_id": "s2wa87k79", + "document": "This strainer makes a great hat, I'll wear it while I serve spaghetti!" + }, + { + "_id": "sroom9j13", + "document": "Why are all these dumpings covered in butter?!" + } + ] +} diff --git a/cypress/fixtures/samples-dummies/TimeSeriesAudioUrl.json b/cypress/fixtures/samples-dummies/TimeSeriesAudioUrl.json new file mode 100644 index 00000000..11932a73 --- /dev/null +++ b/cypress/fixtures/samples-dummies/TimeSeriesAudioUrl.json @@ -0,0 +1,19 @@ +{ + "name": "Time Series", + "interface": { + "type": "time_series", + "timeFormat": "dates", + "enabledTools": ["create-durations", "label-durations"], + "durationLabels": ["@seveibar is speaking"] + }, + "samples": [ + { + "audioUrl": "https://s3.amazonaws.com/datasets.workaround.online/voice-samples/001/voice.mp3", + "annotation": { + "durations": [ + { "start": 500, "end": 2000, "label": "@seveibar is speaking" } + ] + } + } + ] +} diff --git a/cypress/fixtures/samples-dummies/TimeSeriestimeData.json b/cypress/fixtures/samples-dummies/TimeSeriestimeData.json new file mode 100644 index 00000000..e009b000 --- /dev/null +++ b/cypress/fixtures/samples-dummies/TimeSeriestimeData.json @@ -0,0 +1,24 @@ +{ + "name": "Time Series 2", + "interface": { + "type": "time_series", + "timeFormat": "dates", + "enabledTools": ["create-durations", "label-durations"], + "durationLabels": ["@seveibar is speaking"] + }, + "samples": [ + { + "_id": "smzrtu13f", + "timeData": [ + { "time": 0, "value": 0 }, + { "time": 500, "value": 0.75 }, + { "time": 1000, "value": 1 } + ], + "annotation": { + "durations": [ + { "start": 500, "end": 2000, "label": "@seveibar is speaking" } + ] + } + } + ] +} diff --git a/cypress/fixtures/samples-dummies/VideoSegmentation.json b/cypress/fixtures/samples-dummies/VideoSegmentation.json new file mode 100644 index 00000000..ca966b5c --- /dev/null +++ b/cypress/fixtures/samples-dummies/VideoSegmentation.json @@ -0,0 +1,14 @@ +{ + "name": "Video Segmentation", + "interface": { + "type": "video_segmentation", + "labels": ["valid", "invalid"], + "regionTypesAllowed": ["bounding-box", "polygon", "point"] + }, + "samples": [ + { + "_id": "sprtlkb6r", + "videoUrl": "https://s3.amazonaws.com/asset.workaround.online/SampleVideo_1280x720_1mb.mp4" + } + ] +} diff --git a/cypress/integration/aws-test/credentials.spec.js b/cypress/integration/aws-test/credentials.spec.js new file mode 100644 index 00000000..8137cd01 --- /dev/null +++ b/cypress/integration/aws-test/credentials.spec.js @@ -0,0 +1,27 @@ +import enterCredentialsCognitoS3 from "../utils/credentials-test/enter-credentials-cognito-s3" +import enterCredentialsUser from "../utils/credentials-test/enter-credentials-user" +import commandLocalStorage from "../utils/cypress-command/local-storage" +import commandSetLanguage from "../utils/cypress-command/set-language" +commandLocalStorage() +commandSetLanguage() + +Cypress.config("defaultCommandTimeout", 3000) +if (Cypress.env().AWS_IDENTITY_POOL_ID) + describe("Credentials test", () => { + before("Prepare tests", () => { + cy.log("should be able to join the web site") + cy.visit(`http://localhost:6001`) + cy.setLanguage("en") + }) + + beforeEach("Restore local storage", () => { + cy.restoreLocalStorage() + }) + + enterCredentialsCognitoS3() + enterCredentialsUser() + + afterEach("Save local storage", () => { + cy.saveLocalStorage() + }) + }) diff --git a/cypress/integration/aws-test/export.spec.js b/cypress/integration/aws-test/export.spec.js new file mode 100644 index 00000000..1834857e --- /dev/null +++ b/cypress/integration/aws-test/export.spec.js @@ -0,0 +1,46 @@ +import warningHeader from "../utils/aws-unit-test/warning-header-export" + +import commandSetLanguage from "../utils/cypress-command/set-language" +import commandLocalStorage from "../utils/cypress-command/local-storage" +import commandAddAssetToAwsProject from "../utils/cypress-command/add-asset-to-aws-project" +import commandCredentialsAws from "../utils/cypress-command/credentials-aws" +import commandAddProjectToAws from "../utils/cypress-command/add-project-to-aws" +import commandCleanAws from "../utils/cypress-command/clean-aws" + +commandLocalStorage() +commandCredentialsAws() +commandAddAssetToAwsProject() +commandAddProjectToAws() +commandCleanAws() +commandSetLanguage() + +Cypress.config("defaultCommandTimeout", 3000) +if (Cypress.env().AWS_IDENTITY_POOL_ID) + describe("Export aws test", () => { + before("Prepare tests", () => { + cy.log("should be able to join the web site") + cy.visit(`http://localhost:6001`) + cy.createCredentialsAws() + cy.setLanguage("en") + cy.saveLocalStorage() + cy.cleanAws() + cy.addProjectToAws("ImageClassification.json") + cy.addAssetToAwsProject("Image Classification", "image1.jpg") + }) + + beforeEach("Go to import page", () => { + cy.restoreLocalStorage() + }) + + warningHeader() + + //Comment below when debugging 1 test + afterEach("Return to home page", () => { + cy.get("button[title='Exit to Welcome Page']").click({ force: true }) + }) + + //Comment below when debugging aws + after("Clean AWS", () => { + cy.cleanAws() + }) + }) diff --git a/cypress/integration/aws-test/import.spec.js b/cypress/integration/aws-test/import.spec.js new file mode 100644 index 00000000..86f98536 --- /dev/null +++ b/cypress/integration/aws-test/import.spec.js @@ -0,0 +1,40 @@ +import commandLocalStorage from "../utils/cypress-command/local-storage" +import commandCredentialsAws from "../utils/cypress-command/credentials-aws" +import commandCleanAws from "../utils/cypress-command/clean-aws" +import commandSetUpAws from "../utils/cypress-command/set-up-aws" +import commandSetLanguage from "../utils/cypress-command/set-language" + +commandLocalStorage() +commandCredentialsAws() +commandSetUpAws() +commandCleanAws() +commandSetLanguage() + +Cypress.config("defaultCommandTimeout", 3000) +if (Cypress.env().AWS_IDENTITY_POOL_ID) + describe("Import aws test", () => { + before("Prepare tests", () => { + cy.log("should be able to join the web site") + cy.visit(`http://localhost:6001`) + cy.setLanguage("en") + //the following are very long processus try to keep them here so they execute only once + cy.createCredentialsAws() + cy.saveLocalStorage() + cy.cleanAws() + cy.setUpAws() + }) + + beforeEach("Go to import page", () => { + cy.restoreLocalStorage() + }) + + //Comment below when debugging 1 test + afterEach("Return to home page", () => { + cy.get("button[title='Exit to Welcome Page']").click({ force: true }) + }) + + //Comment below when debugging aws + after("Clean AWS", () => { + cy.cleanAws() + }) + }) diff --git a/cypress/integration/collaborative-session.spec.js b/cypress/integration/collaborative-session.spec.js index f098b6cb..826881df 100644 --- a/cypress/integration/collaborative-session.spec.js +++ b/cypress/integration/collaborative-session.spec.js @@ -1,13 +1,14 @@ -import clickOn100SamplesInACollaborativeSession from "../utils/interface-test/click-on-100-samples-in-a-collaborative-session.spec" -import createAndVisitCollaborativeSession from "../utils/interface-test/create-and-visit-collaborative-session.spec" +import clickOn100SamplesInACollaborativeSession from "./utils/interface-test/click-on-100-samples-in-a-collaborative-session" +import createAndVisitCollaborativeSession from "./utils/interface-test/create-and-visit-collaborative-session" +import commandSetLanguage from "./utils/cypress-command/set-language" + +commandSetLanguage() + Cypress.config("defaultCommandTimeout", 3000) describe("Create and Visit Collaborative Session", () => { beforeEach("Prepare test", () => { cy.visit(`http://localhost:6001`) - cy.get('input[id="react-select-2-input"]') - .focus() - .type("English") - .type("{enter}") + cy.setLanguage("en") cy.contains("New File").click() }) createAndVisitCollaborativeSession() diff --git a/cypress/integration/function-verification.spec.js b/cypress/integration/function-verification.spec.js deleted file mode 100644 index e12e88ba..00000000 --- a/cypress/integration/function-verification.spec.js +++ /dev/null @@ -1,4 +0,0 @@ -import getDataUrlTypeTest from "../utils/function-test/get-data-url-type.spec" -describe("Function verification", () => { - getDataUrlTypeTest() -}) diff --git a/cypress/integration/udt-test.spec.js b/cypress/integration/udt-test.spec.js index 1e0e8394..f8496b52 100644 --- a/cypress/integration/udt-test.spec.js +++ b/cypress/integration/udt-test.spec.js @@ -1,27 +1,29 @@ -import createNewFile from "../utils/interface-test/create-new-file.spec" -import imageClassification from "../utils/interface-test/image-classification.spec" -import imageSegmentation from "../utils/interface-test/image-segmentation.spec" -import keyboardShortcuts from "../utils/interface-test/keyboard-shortcuts.spec" -import labelHelp from "../utils/interface-test/label-help.spec" -import namedEntityRecognition from "../utils/interface-test/named-entity-recognition.spec" -import pasteImageUrlsWithCSV from "../utils/interface-test/paste-image-urls-with-csv.spec" -import pasteImageUrls from "../utils/interface-test/paste-image-urls.spec" -import textEntityClassification from "../utils/interface-test/text-entity-classification.spec" +import createNewFile from "./utils/interface-test/create-new-file" +import imageClassification from "./utils/interface-test/image-classification" +import imageSegmentation from "./utils/interface-test/image-segmentation" +import keyboardShortcuts from "./utils/interface-test/keyboard-shortcuts" +import namedEntityRecognition from "./utils/interface-test/named-entity-recognition" +import pasteImageUrlsWithCSV from "./utils/interface-test/paste-image-urls-with-csv" +import pasteImageUrls from "./utils/interface-test/paste-image-urls" +import textEntityClassification from "./utils/interface-test/text-entity-classification" +import defaultTemplate from "./utils/interface-test/default-template" +import templateNonVisible from "./utils/interface-test/template-non-visble" +import commandSetLanguage from "./utils/cypress-command/set-language" + +commandSetLanguage() Cypress.config("defaultCommandTimeout", 3000) describe("Udt test", () => { beforeEach("Prepare test", () => { cy.visit(`http://localhost:6001`) - cy.get('input[id="react-select-2-input"]') - .focus() - .type("English") - .type("{enter}") + cy.setLanguage("en") }) + templateNonVisible() + defaultTemplate() createNewFile() imageClassification() imageSegmentation() keyboardShortcuts() - labelHelp() namedEntityRecognition() pasteImageUrlsWithCSV() pasteImageUrls() diff --git a/cypress/integration/utils/aws-unit-test/warning-header-export.js b/cypress/integration/utils/aws-unit-test/warning-header-export.js new file mode 100644 index 00000000..54b80d4a --- /dev/null +++ b/cypress/integration/utils/aws-unit-test/warning-header-export.js @@ -0,0 +1,22 @@ +import goToImportPage from "../go-to-import-page" +const warningHeader = () => { + it("Warning project name not set", () => { + goToImportPage("Image Segmentation") + cy.contains("Export to S3 (Cognito)").click() + cy.contains("Warning : Please enter a project name.") + cy.contains("Close").click() + }) + it("Warning project already exist", () => { + goToImportPage("Image Segmentation") + cy.contains("Export to S3 (Cognito)").click() + cy.get("input[id='ProjectName']") + .focus() + .clear() + .type("Image Classification") + cy.contains( + "Warning : This project name already exist. If you continue the existing project with the same name will be replaced." + ) + cy.contains("Close").click() + }) +} +export default warningHeader diff --git a/cypress/integration/utils/credentials-test/enter-credentials-cognito-s3.js b/cypress/integration/utils/credentials-test/enter-credentials-cognito-s3.js new file mode 100644 index 00000000..00f6c3b0 --- /dev/null +++ b/cypress/integration/utils/credentials-test/enter-credentials-cognito-s3.js @@ -0,0 +1,58 @@ +const enterCredentialsCognitoS3 = () => { + cy.get('input[placeholder="XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab"]') + .focus() + .type(Cypress.env().AWS_IDENTITY_POOL_ID) + cy.get('input[placeholder="XX-XXXX-X"]') + .first() + .focus() + .type(Cypress.env().AWS_AUTH_REGION) + cy.get('input[placeholder="XX-XXXX-X_12ab34cd9"]') + .focus() + .type(Cypress.env().AWS_USER_POOL_ID) + cy.get('input[placeholder="26-char alphanumeric string"]') + .focus() + .type(Cypress.env().AWS_USER_POOL_WEB_CLIENT_ID) + cy.get('input[placeholder="Name of the bucket"]') + .focus() + .type(Cypress.env().AWS_STORAGE_BUCKET) + cy.get('input[placeholder="XX-XXXX-X"]') + .last() + .focus() + .type(Cypress.env().AWS_STORAGE_REGION) + cy.get('input[class="MuiInputBase-input MuiInput-input"]') + .last() + .focus() + .type(Cypress.env().COGNITO_USER_PASS_LENGTH) + if (Cypress.env().COGNITO_USER_PASS_REQUIRE_LOWERCASE === "TRUE") { + cy.get('input[id="RequireLowercaseYes"]').click().focus().blur() + } else { + cy.get('input[id="RequireLowercaseNo"]').click().focus().blur() + } + if (Cypress.env().COGNITO_USER_PASS_REQUIRE_UPPERCASE === "TRUE") { + cy.get('input[id="RequireUppercaseYes"]').click().focus().blur() + } else { + cy.get('input[id="RequireUppercaseNo"]').click().focus().blur() + } + if (Cypress.env().COGNITO_USER_PASS_REQUIRE_NUMBER === "TRUE") { + cy.get('input[id="RequireNumberYes"]').click().focus().blur() + } else { + cy.get('input[id="RequireNumberNo"]').click().focus().blur() + } + if (Cypress.env().COGNITO_USER_PASS_REQUIRE_SYMBOL === "TRUE") { + cy.get('input[id="RequireSymbolYes"]').click().focus().blur() + } else { + cy.get('input[id="RequireSymbolNo"]').click().focus().blur() + } +} + +const test = () => { + it("Enter credentials cognito-s3", () => { + cy.log("should be able to set s3 config") + cy.contains("Add Authentification").click() + cy.contains("AWS - Cognito").click() + enterCredentialsCognitoS3() + cy.contains("Complete").click() + }) +} + +export default test diff --git a/cypress/integration/utils/credentials-test/enter-credentials-user.js b/cypress/integration/utils/credentials-test/enter-credentials-user.js new file mode 100644 index 00000000..0a6b52e3 --- /dev/null +++ b/cypress/integration/utils/credentials-test/enter-credentials-user.js @@ -0,0 +1,14 @@ +const enterCredentialsUser = () => { + cy.get('input[id="username"]').focus().type(Cypress.env().COGNITO_USER_NAME) + cy.get('input[id="password"]').focus().type(Cypress.env().COGNITO_USER_PASS) +} +const test = () => { + it("Enter credentials user cognito", () => { + cy.log("should be able to set user cognito config") + cy.contains("Cognito").click() + enterCredentialsUser() + cy.get("button[id='sign-in']").click() + cy.get("button[id='sign-in']", { timeout: 30000 }).should("not.exist") + }) +} +export default test diff --git a/cypress/integration/utils/cypress-command/add-asset-to-aws-project.js b/cypress/integration/utils/cypress-command/add-asset-to-aws-project.js new file mode 100644 index 00000000..c589aa48 --- /dev/null +++ b/cypress/integration/utils/cypress-command/add-asset-to-aws-project.js @@ -0,0 +1,42 @@ +import datasetManagerCognito from "udt-dataset-managers/dist/CognitoDatasetManager" +import mime from "mime-types" +const command = () => { + Cypress.Commands.add("addAssetToAwsProject", (nameProject, nameAsset) => { + var credentials = Cypress.env() + cy.log("Add test files : " + nameAsset) + cy.fixture("assets-dummies/" + nameAsset, "base64").then( + { timeout: 100000 }, + async (asset) => { + var blob + if (nameAsset.match(".*\\.json")) { + blob = asset + } else { + blob = await Cypress.Blob.base64StringToBlob( + asset, + mime.lookup(nameAsset) + ) + } + const authConfig = { + Auth: { + identityPoolId: credentials.AWS_IDENTITY_POOL_ID, + region: credentials.AWS_AUTH_REGION, + userPoolId: credentials.AWS_USER_POOL_ID, + userPoolWebClientId: credentials.AWS_USER_POOL_WEB_CLIENT_ID, + mandatorySignIn: credentials.AWS_MANDATORY_SIGN_IN, + authenticationFlowType: credentials.AWS_AUTHENTICATION_FLOW_TYPE, + }, + Storage: { + AWSS3: { + bucket: credentials.AWS_STORAGE_BUCKET, + region: credentials.AWS_STORAGE_REGION, + }, + }, + } + const ds = await new datasetManagerCognito({ authConfig }) + ds.setProject(nameProject) + await ds.addAsset(nameAsset, blob) + } + ) + }) +} +export default command diff --git a/cypress/integration/utils/cypress-command/add-project-to-aws.js b/cypress/integration/utils/cypress-command/add-project-to-aws.js new file mode 100644 index 00000000..dd8ebd30 --- /dev/null +++ b/cypress/integration/utils/cypress-command/add-project-to-aws.js @@ -0,0 +1,31 @@ +import datasetManagerCognito from "udt-dataset-managers/dist/CognitoDatasetManager" +const command = () => { + Cypress.Commands.add("addProjectToAws", (nameDummies) => { + var credentials = Cypress.env() + cy.log("Add test files : " + nameDummies) + cy.fixture("samples-dummies/" + nameDummies).then( + { timeout: 100000 }, + async (dummies) => { + const authConfig = { + Auth: { + identityPoolId: credentials.AWS_IDENTITY_POOL_ID, + region: credentials.AWS_AUTH_REGION, + userPoolId: credentials.AWS_USER_POOL_ID, + userPoolWebClientId: credentials.AWS_USER_POOL_WEB_CLIENT_ID, + mandatorySignIn: credentials.AWS_MANDATORY_SIGN_IN, + authenticationFlowType: credentials.AWS_AUTHENTICATION_FLOW_TYPE, + }, + Storage: { + AWSS3: { + bucket: credentials.AWS_STORAGE_BUCKET, + region: credentials.AWS_STORAGE_REGION, + }, + }, + } + const ds = await new datasetManagerCognito({ authConfig }) + await ds.setDataset(dummies) + } + ) + }) +} +export default command diff --git a/cypress/integration/utils/cypress-command/clean-aws.js b/cypress/integration/utils/cypress-command/clean-aws.js new file mode 100644 index 00000000..ddee545d --- /dev/null +++ b/cypress/integration/utils/cypress-command/clean-aws.js @@ -0,0 +1,33 @@ +import commandRemoveAwsProject from "./remove-aws-project" +const command = () => { + commandRemoveAwsProject() + Cypress.Commands.add("cleanAws", () => { + cy.log("Start cleaning aws") + cy.removeAwsProject("Not Supported") + cy.removeAwsProject("Image Classification") + cy.removeAwsProject("Image Segmentation") + cy.removeAwsProject("Time Series") + cy.removeAwsProject("Time Series 2") + cy.removeAwsProject("Data Entry") + cy.removeAwsProject("Text Classification") + cy.removeAwsProject("Video Segmentation") + cy.removeAwsProject("Audio Transcription") + cy.removeAwsProject("Empty") + cy.removeAwsProject("Rename Test") + cy.removeAwsProject("CypressTestExportAnnotationOnlyTime") + cy.removeAwsProject("CypressTestExportAnnotationOnlyImage") + cy.removeAwsProject("CypressTestExportAnnotationOnlyVideo") + cy.removeAwsProject("CypressTestExportAnnotationOnlyPDF") + cy.removeAwsProject("CypressTestExportAnnotationOnlyAudio") + cy.removeAwsProject("CypressTestExportAnnotationOnlyText") + cy.removeAwsProject("CypressTestExportAssetsTime") + cy.removeAwsProject("CypressTestExportAssetsTime2") + cy.removeAwsProject("CypressTestExportAssetsImage") + cy.removeAwsProject("CypressTestExportAssetsVideo") + cy.removeAwsProject("CypressTestExportAssetsPDF") + cy.removeAwsProject("CypressTestExportAssetsAudio") + cy.removeAwsProject("CypressTestExportAssetsText") + cy.log("End cleaning aws") + }) +} +export default command diff --git a/cypress/integration/utils/cypress-command/credentials-aws.js b/cypress/integration/utils/cypress-command/credentials-aws.js new file mode 100644 index 00000000..46048ac3 --- /dev/null +++ b/cypress/integration/utils/cypress-command/credentials-aws.js @@ -0,0 +1,78 @@ +import Amplify, { Auth } from "aws-amplify" + +const command = () => { + Cypress.Commands.add("createCredentialsAws", () => { + cy.then({ timeout: 10000 }, async () => { + const app_config = { + "auth.cognito.identityPoolId": Cypress.env().AWS_IDENTITY_POOL_ID, + "auth.cognito.region": Cypress.env().AWS_AUTH_REGION, + "auth.cognito.userPoolId": Cypress.env().AWS_USER_POOL_ID, + "auth.cognito.userPoolWebClientId": Cypress.env() + .AWS_USER_POOL_WEB_CLIENT_ID, + "auth.cognito.storage.awsS3.bucket": Cypress.env().AWS_STORAGE_BUCKET, + "auth.cognito.storage.awsS3.region": Cypress.env().AWS_STORAGE_REGION, + "auth.cognito.password.minimumLength": Cypress.env() + .COGNITO_USER_PASS_LENGTH, + "auth.cognito.password.requireLowercase": + Cypress.env().COGNITO_USER_PASS_REQUIRE_LOWERCASE === "TRUE" + ? true + : false, + "auth.cognito.password.requireUppercase": + Cypress.env().COGNITO_USER_PASS_REQUIRE_UPPERCASE === "TRUE" + ? true + : false, + "auth.cognito.password.requireNumbers": + Cypress.env().COGNITO_USER_PASS_REQUIRE_NUMBER === "TRUE" + ? true + : false, + "auth.cognito.password.requireSymbols": + Cypress.env().COGNITO_USER_PASS_REQUIRE_SYMBOL === "TRUE" + ? true + : false, + "auth.provider": "cognito", + provider: "cognito", + } + const json = { + Auth: { + identityPoolId: Cypress.env().AWS_IDENTITY_POOL_ID, + region: Cypress.env().AWS_AUTH_REGION, + userPoolId: Cypress.env().AWS_USER_POOL_ID, + userPoolWebClientId: Cypress.env().AWS_USER_POOL_WEB_CLIENT_ID, + mandatorySignIn: true, + authenticationFlowType: "USER_PASSWORD_AUTH", + minimumLength: Cypress.env().COGNITO_USER_PASS_LENGTH, + requireNumbers: + Cypress.env().COGNITO_USER_PASS_REQUIRE_NUMBER === "TRUE" + ? true + : false, + requireSymbols: + Cypress.env().COGNITO_USER_PASS_REQUIRE_SYMBOL === "TRUE" + ? true + : false, + requireUppercase: + Cypress.env().COGNITO_USER_PASS_REQUIRE_UPPERCASE === "TRUE" + ? true + : false, + requireLowercase: + Cypress.env().COGNITO_USER_PASS_REQUIRE_LOWERCASE === "TRUE" + ? true + : false, + }, + Storage: { + AWSS3: { + bucket: Cypress.env().AWS_STORAGE_BUCKET, + region: Cypress.env().AWS_STORAGE_REGION, + }, + }, + } + localStorage.setItem("app_config", JSON.stringify(app_config)) + Amplify.configure(json) + await Auth.signIn( + Cypress.env().COGNITO_USER_NAME, + Cypress.env().COGNITO_USER_PASS + ) + }) + cy.reload() + }) +} +export default command diff --git a/cypress/integration/utils/cypress-command/local-storage.js b/cypress/integration/utils/cypress-command/local-storage.js new file mode 100644 index 00000000..9fc5dc83 --- /dev/null +++ b/cypress/integration/utils/cypress-command/local-storage.js @@ -0,0 +1,15 @@ +//https://github.com/cypress-io/cypress/issues/461#issuecomment-325402086 +const command = () => { + let LOCAL_STORAGE_MEMORY = {} + Cypress.Commands.add("saveLocalStorage", () => { + Object.keys(localStorage).forEach((key) => { + LOCAL_STORAGE_MEMORY[key] = localStorage[key] + }) + }) + Cypress.Commands.add("restoreLocalStorage", () => { + Object.keys(LOCAL_STORAGE_MEMORY).forEach((key) => { + localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]) + }) + }) +} +export default command diff --git a/cypress/integration/utils/cypress-command/remove-aws-project.js b/cypress/integration/utils/cypress-command/remove-aws-project.js new file mode 100644 index 00000000..3217089e --- /dev/null +++ b/cypress/integration/utils/cypress-command/remove-aws-project.js @@ -0,0 +1,26 @@ +import datasetManagerCognito from "udt-dataset-managers/dist/CognitoDatasetManager" + +const command = () => { + Cypress.Commands.add("removeAwsProject", async (name) => { + var credentials = Cypress.env() + const authConfig = { + Auth: { + identityPoolId: credentials.AWS_IDENTITY_POOL_ID, + region: credentials.AWS_AUTH_REGION, + userPoolId: credentials.AWS_USER_POOL_ID, + userPoolWebClientId: credentials.AWS_USER_POOL_WEB_CLIENT_ID, + mandatorySignIn: credentials.AWS_MANDATORY_SIGN_IN, + authenticationFlowType: credentials.AWS_AUTHENTICATION_FLOW_TYPE, + }, + Storage: { + AWSS3: { + bucket: credentials.AWS_STORAGE_BUCKET, + region: credentials.AWS_STORAGE_REGION, + }, + }, + } + const ds = await new datasetManagerCognito({ authConfig }) + await ds.removeProject(name) + }) +} +export default command diff --git a/cypress/integration/utils/cypress-command/set-language.js b/cypress/integration/utils/cypress-command/set-language.js new file mode 100644 index 00000000..fdac5d56 --- /dev/null +++ b/cypress/integration/utils/cypress-command/set-language.js @@ -0,0 +1,8 @@ +const command = (langChar) => { + //Possible input en,fr,cn.dl and pt + Cypress.Commands.add("setLanguage", () => { + localStorage.setItem("i18nextLng", langChar) + cy.reload() + }) +} +export default command diff --git a/cypress/integration/utils/cypress-command/set-template.js b/cypress/integration/utils/cypress-command/set-template.js new file mode 100644 index 00000000..3bfa1b48 --- /dev/null +++ b/cypress/integration/utils/cypress-command/set-template.js @@ -0,0 +1,10 @@ +const command = () => { + Cypress.Commands.add("setTemplate", (template) => { + cy.log("Set template") + var appConfig = localStorage.getItem("app_config") + appConfig = JSON.parse(appConfig) + appConfig.defaultTemplate = template + localStorage.setItem("app_config", JSON.stringify(appConfig)) + }) +} +export default command diff --git a/cypress/integration/utils/cypress-command/set-up-aws.js b/cypress/integration/utils/cypress-command/set-up-aws.js new file mode 100644 index 00000000..98e9934c --- /dev/null +++ b/cypress/integration/utils/cypress-command/set-up-aws.js @@ -0,0 +1,29 @@ +import commandAddAssetToAwsProject from "./add-asset-to-aws-project" +import commandAddProjectToAws from "./add-project-to-aws" +const command = () => { + commandAddAssetToAwsProject() + commandAddProjectToAws() + Cypress.Commands.add("setUpAws", () => { + cy.addProjectToAws("ImageClassification.json") + cy.addProjectToAws("Empty.json") + cy.addProjectToAws("AudioTranscription.json") + cy.addProjectToAws("VideoSegmentation.json") + cy.addProjectToAws("TextClassification.json") + cy.addProjectToAws("TimeSeriesTimeData.json") + cy.addProjectToAws("TimeSeriesAudioUrl.json") + cy.addProjectToAws("DataEntry.json") + cy.addProjectToAws("NotSupported.json") + cy.addAssetToAwsProject("Image Classification", "image1.jpg") + cy.addAssetToAwsProject("Image Classification", "image2.jpg") + cy.addAssetToAwsProject("Audio Transcription", "audio.mp3") + cy.addAssetToAwsProject("Video Segmentation", "video.mp4") + cy.addAssetToAwsProject("Data Entry", "pdf1.pdf") + cy.addAssetToAwsProject("Data Entry", "pdf2.pdf") + cy.addAssetToAwsProject("Text Classification", "text1.txt") + cy.addAssetToAwsProject("Text Classification", "text2.txt") + cy.addAssetToAwsProject("Text Classification", "text3.txt") + cy.addAssetToAwsProject("Time Series", "audio.mp3") + cy.addAssetToAwsProject("Time Series 2", "timeSeries.json") + }) +} +export default command diff --git a/cypress/utils/function-test/get-data-url-type.spec.js b/cypress/integration/utils/function-test/get-data-url-type.js similarity index 90% rename from cypress/utils/function-test/get-data-url-type.spec.js rename to cypress/integration/utils/function-test/get-data-url-type.js index 8569dfeb..430930b8 100644 --- a/cypress/utils/function-test/get-data-url-type.spec.js +++ b/cypress/integration/utils/function-test/get-data-url-type.js @@ -1,4 +1,4 @@ -import getDataUrlType from "../../../src/utils/get-data-url-type" +import getDataUrlType from "../../../dist/utils/get-data-url-type" const getDataUrlTypeTest = () => { it("Check getDataUrlType", () => { expect( @@ -18,7 +18,7 @@ const getDataUrlTypeTest = () => { "PDF" ) expect(getDataUrlType("https://arxiv.org/pdf/1908.07069.txt")).to.equal( - "Texte" + "Text" ) expect(getDataUrlType("https://arxiv.org/pdf/1908.07069.js")).to.equal( "File" diff --git a/cypress/integration/utils/go-to-import-page.js b/cypress/integration/utils/go-to-import-page.js new file mode 100644 index 00000000..15356312 --- /dev/null +++ b/cypress/integration/utils/go-to-import-page.js @@ -0,0 +1,10 @@ +const test = (typeProject) => { + cy.log("should be able to go to the import page") + cy.contains("New File", { timeout: 50000 }).click() + if (typeProject) cy.contains(typeProject).click() + cy.get('button[id="tab-samples"]').click() + cy.contains("Samples").click() + cy.contains("Import").click() +} + +export default test diff --git a/cypress/utils/interface-test/click-on-100-samples-in-a-collaborative-session.spec.js b/cypress/integration/utils/interface-test/click-on-100-samples-in-a-collaborative-session.js similarity index 100% rename from cypress/utils/interface-test/click-on-100-samples-in-a-collaborative-session.spec.js rename to cypress/integration/utils/interface-test/click-on-100-samples-in-a-collaborative-session.js diff --git a/cypress/utils/interface-test/create-and-visit-collaborative-session.spec.js b/cypress/integration/utils/interface-test/create-and-visit-collaborative-session.js similarity index 81% rename from cypress/utils/interface-test/create-and-visit-collaborative-session.spec.js rename to cypress/integration/utils/interface-test/create-and-visit-collaborative-session.js index 7c58324b..c6b0ca3a 100644 --- a/cypress/utils/interface-test/create-and-visit-collaborative-session.spec.js +++ b/cypress/integration/utils/interface-test/create-and-visit-collaborative-session.js @@ -2,15 +2,15 @@ const createAndVisitCollaborativeSession = () => { let collaborationUrl it("Should be able to create and visit collaborative session", () => { cy.log("should be able to import Elon Musk Tweets dataset") - cy.get("#tab-samples", { timeout: 5000 }).click() + cy.get("#tab-samples", { timeout: 10000 }).click() cy.contains("Import").click() cy.contains("Import Toy Dataset").click() cy.contains("Elon Musk Tweets").siblings("td").eq(2).click() cy.log("should be able to create new session") - cy.get("div[title='collaborate-icon']").click() + cy.get("div[title='collaborate-icon']", { timeout: 10000 }).click() cy.contains("Create New Session", { timeout: 5000 }).click() - cy.contains("Leave Session", { timeout: 10000 }) + cy.contains("Leave Session", { timeout: 20000 }) cy.get("div[title='collaborate-icon']").trigger("mouseleave") cy.log("should be able to store session url") @@ -25,7 +25,7 @@ const createAndVisitCollaborativeSession = () => { cy.visit(collaborationUrl) cy.log("should be able to navigate to samples") - cy.get("#tab-samples").click() + cy.get("#tab-samples", { timeout: 20000 }).click() }) }) } diff --git a/cypress/utils/interface-test/create-new-file.spec.js b/cypress/integration/utils/interface-test/create-new-file.js similarity index 95% rename from cypress/utils/interface-test/create-new-file.spec.js rename to cypress/integration/utils/interface-test/create-new-file.js index f7f7e24e..2fa6e9cb 100644 --- a/cypress/utils/interface-test/create-new-file.spec.js +++ b/cypress/integration/utils/interface-test/create-new-file.js @@ -1,7 +1,8 @@ const createNewFile = () => { - it("Should be able to select all the interfaces", () => { + it.skip("Should be able to select all the interfaces", () => { cy.contains("New File").click() cy.contains("Image Segmentation").click() + cy.wait(200) cy.matchImageSnapshot("image_segmentation", { failureThresholdType: "percent", }) diff --git a/cypress/integration/utils/interface-test/default-template.js b/cypress/integration/utils/interface-test/default-template.js new file mode 100644 index 00000000..4be72d5a --- /dev/null +++ b/cypress/integration/utils/interface-test/default-template.js @@ -0,0 +1,16 @@ +import commandSetTemplate from "../cypress-command/set-template" +const defaultTemplate = () => { + commandSetTemplate() + it("Should be able to set a default template", () => { + cy.setTemplate("Image Segmentation") + cy.contains("New File").click() + cy.get( + "button[class='MuiButtonBase-root MuiTab-root MuiTab-textColorInherit MuiTab-labelIcon']", + { timeout: 2000 } + ) + .eq(2) + .click() + cy.contains("image_segmentation") + }) +} +export default defaultTemplate diff --git a/cypress/utils/interface-test/image-classification.spec.js b/cypress/integration/utils/interface-test/image-classification.js similarity index 96% rename from cypress/utils/interface-test/image-classification.spec.js rename to cypress/integration/utils/interface-test/image-classification.js index 04c269cd..0de2a650 100644 --- a/cypress/utils/interface-test/image-classification.spec.js +++ b/cypress/integration/utils/interface-test/image-classification.js @@ -25,7 +25,7 @@ const imageClassification = () => { .type("not ai generated") cy.log("should be able to see samples") - cy.get("#tab-samples").click() + cy.get("#tab-samples", { timeout: 5000 }).click() cy.log("should be able to open 21st sample") cy.contains("21").click() diff --git a/cypress/utils/interface-test/image-segmentation.spec.js b/cypress/integration/utils/interface-test/image-segmentation.js similarity index 100% rename from cypress/utils/interface-test/image-segmentation.spec.js rename to cypress/integration/utils/interface-test/image-segmentation.js diff --git a/cypress/utils/interface-test/keyboard-shortcuts.spec.js b/cypress/integration/utils/interface-test/keyboard-shortcuts.js similarity index 100% rename from cypress/utils/interface-test/keyboard-shortcuts.spec.js rename to cypress/integration/utils/interface-test/keyboard-shortcuts.js diff --git a/cypress/integration/utils/interface-test/language-box.js b/cypress/integration/utils/interface-test/language-box.js new file mode 100644 index 00000000..438048f6 --- /dev/null +++ b/cypress/integration/utils/interface-test/language-box.js @@ -0,0 +1,32 @@ +const setLanguage = (language, langChar) => { + cy.log("should be able to set the language to " + language) + cy.get('input[id="react-select-2-input"]') + .focus() + .type(language) + .type("{enter}") + .should(() => { + cy.expect(localStorage.getItem("i18nextLng"), { + timeout: 2000, + }).to.be.equal(langChar) + }) +} + +const test = () => { + it("Should be able to set english language from text", () => { + setLanguage("English", "en") + }) + it("Should be able to set french language from text", () => { + setLanguage("French", "fr") + }) + it("Should be able to set chinese language from text", () => { + setLanguage("Chinese", "cn") + }) + it("Should be able to set portugese language from text", () => { + setLanguage("Portuguese", "pt") + }) + it("Should be able to set dutch language from text", () => { + setLanguage("Dutch", "nl") + }) +} + +export default test diff --git a/cypress/utils/interface-test/named-entity-recognition.spec.js b/cypress/integration/utils/interface-test/named-entity-recognition.js similarity index 97% rename from cypress/utils/interface-test/named-entity-recognition.spec.js rename to cypress/integration/utils/interface-test/named-entity-recognition.js index e22b43b3..ad6342c8 100644 --- a/cypress/utils/interface-test/named-entity-recognition.spec.js +++ b/cypress/integration/utils/interface-test/named-entity-recognition.js @@ -15,7 +15,7 @@ const namedEntityRecognition = () => { cy.contains("Elon Musk Tweets").siblings("td").eq(2).click() cy.log("should be able to setup Named Entity Recognition") - cy.get("#tab-setup").click() + cy.get("#tab-setup", { timeout: 5000 }).click() cy.contains("Named Entity Recognition").click() cy.get("input[value=food]").focus().clear().type("mars") cy.get("input[value=Food]").focus().clear().type("About Mars") diff --git a/cypress/utils/interface-test/paste-image-urls-with-csv.spec.js b/cypress/integration/utils/interface-test/paste-image-urls-with-csv.js similarity index 100% rename from cypress/utils/interface-test/paste-image-urls-with-csv.spec.js rename to cypress/integration/utils/interface-test/paste-image-urls-with-csv.js diff --git a/cypress/utils/interface-test/paste-image-urls.spec.js b/cypress/integration/utils/interface-test/paste-image-urls.js similarity index 100% rename from cypress/utils/interface-test/paste-image-urls.spec.js rename to cypress/integration/utils/interface-test/paste-image-urls.js diff --git a/cypress/integration/utils/interface-test/template-non-visble.js b/cypress/integration/utils/interface-test/template-non-visble.js new file mode 100644 index 00000000..efe82b39 --- /dev/null +++ b/cypress/integration/utils/interface-test/template-non-visble.js @@ -0,0 +1,8 @@ +const templateNonVisible = () => { + it("time series 2 should not be visible", () => { + cy.contains("New File").click() + cy.contains("Time Series 2").should("not.exist") + }) +} + +export default templateNonVisible diff --git a/cypress/utils/interface-test/text-entity-classification.spec.js b/cypress/integration/utils/interface-test/text-entity-classification.js similarity index 100% rename from cypress/utils/interface-test/text-entity-classification.spec.js rename to cypress/integration/utils/interface-test/text-entity-classification.js diff --git a/cypress/integration/utils/remove-cypress-file-in-aws.js b/cypress/integration/utils/remove-cypress-file-in-aws.js new file mode 100644 index 00000000..8ec8664b --- /dev/null +++ b/cypress/integration/utils/remove-cypress-file-in-aws.js @@ -0,0 +1,29 @@ +import datasetManagerCognito from "udt-dataset-managers/dist/CognitoDatasetManager" + +const removeAWSFile = (name) => { + var credentials = Cypress.env() + cy.then( + async () => { + const authConfig = { + Auth: { + identityPoolId: credentials.AWS_IDENTITY_POOL_ID, + region: credentials.AWS_AUTH_REGION, + userPoolId: credentials.AWS_USER_POOL_ID, + userPoolWebClientId: credentials.AWS_USER_POOL_WEB_CLIENT_ID, + mandatorySignIn: credentials.AWS_MANDATORY_SIGN_IN, + authenticationFlowType: credentials.AWS_AUTHENTICATION_FLOW_TYPE, + }, + Storage: { + AWSS3: { + bucket: credentials.AWS_STORAGE_BUCKET, + region: credentials.AWS_STORAGE_REGION, + }, + }, + } + const ds = await new datasetManagerCognito({ authConfig }) + await ds.removeProject(name) + }, + { timeout: 10000 } + ) +} +export default removeAWSFile diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js index af71bd23..e2ec967a 100644 --- a/cypress/plugins/index.js +++ b/cypress/plugins/index.js @@ -19,7 +19,18 @@ const { addMatchImageSnapshotPlugin } = require("cypress-image-snapshot/plugin") module.exports = (on, config) => { + const options = { + outputRoot: config.projectRoot + "/logs/", + outputTarget: { + "out.txt": "txt", + "out.json": "json", + }, + printLogsToConsole: "never", + } // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config - addMatchImageSnapshotPlugin(on, config) + addMatchImageSnapshotPlugin(on, config), + require("@cypress/react/plugins/react-scripts")(on, config) + require("cypress-terminal-report/src/installLogsPrinter")(on, options) + return config } diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 21af06ca..7df87747 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -24,7 +24,6 @@ // -- This will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) import { addMatchImageSnapshotCommand } from "cypress-image-snapshot/command" - // https://github.com/abramenal/cypress-file-upload import "cypress-file-upload" diff --git a/cypress/support/index.js b/cypress/support/index.js index a80764cb..559d89b9 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -15,6 +15,7 @@ // Import commands.js using ES2015 syntax: import "./commands" +require("cypress-terminal-report/src/installLogsCollector")() // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/cypress/utils/interface-test/label-help.spec.js b/cypress/utils/interface-test/label-help.spec.js deleted file mode 100644 index 8d076784..00000000 --- a/cypress/utils/interface-test/label-help.spec.js +++ /dev/null @@ -1,22 +0,0 @@ -const labelHelp = () => { - it("Should be able to use label help", () => { - cy.contains("Start from Template").click() - cy.contains("Image Classification").click() - cy.get("#tab-samples").click() - cy.contains("Import").click() - cy.contains("Import Toy Dataset").click() - cy.get('[data-import-toy-dataset-name="Cats"]').click() - cy.get("#tab-label").click() - cy.contains("Crowd Label").click() - // This is a special api key that triggers mock functionality from the server - // e.g. it always has 100 credits - cy.get(".label-help-api-key-text-field").type( - "7d773e8566102c1f971e1b52254e1749" - ) - cy.contains("Save").click() - cy.wait(1000) - cy.contains("Start Label Help").click() - }) -} - -export default labelHelp diff --git a/package.json b/package.json index ceab4491..dc37f092 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "universal-data-tool", - "version": "0.14.19", + "version": "0.14.26", "license": "MIT", "main": "desktop/main.js", "homepage": "https://universaldatatool.com/app/", "proxy": "http://localhost:3000", "scripts": { "start": "cross-env PORT=6001 react-scripts start", - "start:desktop": "cross-env BROWSER=none USE_DEV_SERVER=yes concurrently 'npm run start' 'electron ./desktop'", + "start:desktop": "cross-env BROWSER=none USE_DEV_SERVER=yes concurrently 'start' 'electron ./desktop'", "start:desktop:static": "electron ./desktop", "start:web:static": "concurrently 'node ./add-preloaded-app-config.js && serve -s build -p 3000' 'udt-collaboration-server --port 3001'", "build": "npm run build:web", @@ -26,14 +26,11 @@ "storybook": "start-storybook -p 6002 -s public", "build-storybook": "build-storybook -s public", "gh-pages": "npm run build:web && npm run build:vanilla && cp lib/vanilla.js build/vanilla.js && cp ./CNAME ./build/CNAME && gh-pages -d build", - "prettier": "prettier --write \"src/**/*.js\"", + "prettier": "prettier --write .", "test:prettier": "prettier --check \"src/**/*.js\"", "test:lint": "eslint src --max-warnings=0", - "test:integration:dev": "./node_modules/cypress/bin/cypress open", - "test:integration": "./node_modules/cypress/bin/cypress run --env failOnSnapshotDiff=false" - }, - "eslintConfig": { - "extends": "react-app" + "test:integration:dev": "dotenv cypress open", + "test:integration": "dotenv cypress run failOnSnapshotDiff=false" }, "browserslist": { "production": [ @@ -45,33 +42,37 @@ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" + ], + "test": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" ] }, "devDependencies": { - "@babel/cli": "^7.5.0", - "@babel/core": "^7.5.4", - "@babel/plugin-proposal-optional-chaining": "^7.10.1", + "@babel/cli": "^7.12.13", + "@babel/core": "^7.12.13", + "@cypress/react": "^4.16.4", "@material-ui/core": "^4.9.5", "@material-ui/icons": "^4.9.1", "@storybook/addon-actions": "^5.3.19", "@storybook/addon-links": "^5.3.19", "@storybook/addons": "^5.3.19", "@storybook/react": "^5.3.19", - "@testing-library/react-hooks": "^3.2.1", - "ava": "^3.7.0", - "chroma-js": "^2.0.4", - "concurrently": "^5.2.0", - "cross-env": "^7.0.0", - "cypress": "^4.4.0", + "ava": "^3.15.0", + "babel-eslint": "^10.1.0", + "concurrently": "^5.3.0", + "cypress": "^6.7.0", "cypress-file-upload": "^4.0.6", "cypress-image-snapshot": "^3.1.1", - "electron": "^8.0.0", + "cypress-terminal-report": "^2.4.0", + "electron": "^11.2.3", "electron-builder": "^22.8.0", "electron-builder-notarize": "^1.2.0", + "eslint-plugin-cypress": "^2.11.2", "gh-pages": "^2.1.1", - "material-survey": "^1.0.40", "parcel": "^1.12.4", - "prettier": "^2.0.2", + "prettier": "^2.2.1", "react": "^16.8.6", "react-dom": "^16.8.6", "react-markdown": "^4.1.0", @@ -84,33 +85,31 @@ "@semantic-release/git": "^9.0.0", "@sentry/browser": "^5.15.4", "any-shell-escape": "^0.1.1", - "aws-amplify": "^3.0.6", - "aws-sign": "^1.0.0", + "aws-amplify": "^3.3.18", "aws4fetch": "^1.0.12", - "axios": "^0.19.2", + "axios": "^0.21.1", "bent": "^7.1.0", "brace": "^0.11.1", + "cross-env": "^7.0.3", "detect-browser": "^5.0.0", + "dotenv-cli": "^4.0.0", "download-file": "^0.1.5", "duration": "^0.2.2", - "fast-json-patch": "^3.0.0-1", "fast-xml-parser": "^3.17.4", "ffmpeg-static": "^4.2.4", - "form-data": "^3.0.0", - "i18next": "^19.4.4", + "i18next": "^19.9.2", "i18next-browser-languagedetector": "^4.2.0", "in-browser-download": "^2.0.0", "jac-format": "^1.1.3", "js-md5": "^0.7.3", - "mime-types": "^2.1.27", + "material-survey": "^1.0.41", + "mime-types": "^2.1.28", "moment": "^2.24.0", "nan": "^2.14.1", - "posthog-js": "^1.0.4", "qs": "^6.9.4", "react-ace": "^7.0.4", "react-data-table-component": "^6.2.2", "react-dropzone": "^11.0.3", - "react-github-btn": "^1.2.0", "react-hotkeys": "^2.0.0", "react-i18next": "^11.4.0", "react-icons": "^3.9.0", @@ -118,18 +117,17 @@ "react-material-workspace-layout": "^1.0.9", "react-scripts": "^3.4.1", "react-select": "^3.0.8", - "react-time-series": "^1.0.20", + "react-time-series": "^1.0.21", "recoil": "^0.0.13", "rfc6902": "^3.0.4", "seamless-immutable": "^7.1.4", "seamless-immutable-patch": "^1.0.4", "seed-random": "^2.2.0", - "seedrandom": "^3.0.5", "serve": "^11.3.2", "styled-components": "^5.0.0", - "udt-collaboration-server": "^1.0.7", - "udt-dataset-managers": "^1.0.15", - "udt-format": "0.0.1", + "udt-collaboration-server": "^1.0.8", + "udt-dataset-managers": "^1.0.16", + "udt-format": "^0.0.1", "use-async-effect": "^2.2.2", "use-event-callback": "^0.1.0", "wavesurfer.js": "^3.3.3", @@ -160,11 +158,11 @@ "publish": { "provider": "github", "releaseType": "release" + }, + "ava": { + "nodeArguments": [ + "--experimental-modules" + ] } - }, - "ava": { - "nodeArguments": [ - "--experimental-modules" - ] } } diff --git a/public/index.html b/public/index.html index bac6bc24..98a52097 100644 --- a/public/index.html +++ b/public/index.html @@ -29,58 +29,6 @@ text-transform: none; } -