Skip to content

Commit

Permalink
Merge pull request #4608 from wix/feat/migrate-to-new-serverless
Browse files Browse the repository at this point in the history
chore(migration): migrate to a new Copilot prompt-handler service.
  • Loading branch information
asafkorem authored Oct 19, 2024
2 parents f97c747 + 9ed1271 commit e4705c3
Show file tree
Hide file tree
Showing 14 changed files with 396 additions and 377 deletions.
2 changes: 1 addition & 1 deletion detox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"caf": "^15.0.1",
"chalk": "^4.0.0",
"child-process-promise": "^2.2.0",
"detox-copilot": "^0.0.14",
"detox-copilot": "^0.0.23",
"execa": "^5.1.1",
"find-up": "^5.0.0",
"fs-extra": "^11.0.0",
Expand Down
213 changes: 122 additions & 91 deletions detox/src/copilot/detoxCopilotFrameworkDriver.js

Large diffs are not rendered by default.

310 changes: 178 additions & 132 deletions detox/test/detox_copilot_cache.json

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions detox/test/e2e/copilot/01.copilot.sanity.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
const PromptHandler = require('./PromptHandler');
const {describeForCopilotEnv} = require("../utils/custom-describes");

describeForCopilotEnv('Copilot Sanity', () => {
beforeAll(async () => {
await copilot.init(new PromptHandler());

await copilot.perform('Launch the app');
});

Expand Down
19 changes: 7 additions & 12 deletions detox/test/e2e/copilot/02.copilot.actions.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
const PromptHandler = require('./PromptHandler');
const {describeForCopilotEnv} = require("../utils/custom-describes");
const jestExpect = require('expect').default;

describeForCopilotEnv('Copilot Actions', () => {
beforeAll(async () => {
copilot.init(new PromptHandler());

await copilot.perform('Start the application');
});

Expand Down Expand Up @@ -39,16 +36,15 @@ describeForCopilotEnv('Copilot Actions', () => {

it('should long press with point', async () => {
await copilot.perform(
'Long press the top left corner of the "Long Press on Top Left" button',
'Long press the top-most left-most corner of the "Long Press on Top Left" button',
'The text "Long Press on Top Left Working!!!" appears'
);
});

it('should not succeed in long pressing with point outside the target area', async () => {
await copilot.perform(
'Attempt a long press outside the "Long Press on Top Left" button',
'The message "Long Press on Top Left Working!!!" is not present'
);
await jestExpect(async () =>
await copilot.perform('Attempt a long press on the "Long Press on Top Left" button outside its bounds')
).rejects.toThrowError();
});

it('should type in an element', async () => {
Expand Down Expand Up @@ -89,7 +85,7 @@ describeForCopilotEnv('Copilot Actions', () => {

it('should swipe down until pull to reload is triggered', async () => {
await copilot.perform(
'Swipe fast the scrollable area ScrollView799 downwards until the refresh is activated',
'Swipe fast the scrollable area ScrollView799 downwards to activate the pull-to-reload',
'The text "PullToReload Working!!!" becomes visible'
);
});
Expand All @@ -98,8 +94,7 @@ describeForCopilotEnv('Copilot Actions', () => {
await copilot.perform(
'The element with text "Text1" can be seen',
'Swipe the view "ScrollView161" upwards',
'The text element is no longer in view',
// To avoid confusion: up swipe scrolls down
'The Text1 element is no longer in view',
'Swipe the element back up until the "Text1" element is visible',
);
});
Expand Down Expand Up @@ -144,7 +139,7 @@ describeForCopilotEnv('Copilot Actions', () => {

it('should assert on ambiguous intent', async () => {
await jestExpect(async () =>
await copilot.perform('Hello world')
await copilot.perform('Do magic to the element')
).rejects.toThrowError();
});
});
2 changes: 0 additions & 2 deletions detox/test/e2e/copilot/03.copilot.shape-match.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
const PromptHandler = require('./PromptHandler');
const {describeForCopilotEnv} = require("../utils/custom-describes");

describeForCopilotEnv('Shape Match Game Screen', () => {
beforeAll(async () => {
await copilot.init(new PromptHandler());
await copilot.perform('Launch the app');
});

Expand Down
4 changes: 1 addition & 3 deletions detox/test/e2e/copilot/04.webview.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
const PromptHandler = require('./PromptHandler');
const {describeForCopilotEnv} = require("../utils/custom-describes");

describeForCopilotEnv('WebView Interactions', () => {
beforeAll(async () => {
await copilot.init(new PromptHandler());
await copilot.perform('Start the app');
});

Expand Down Expand Up @@ -44,7 +42,7 @@ describeForCopilotEnv('WebView Interactions', () => {

it('should interact with elements in multiple WebViews', async () => {
await copilot.perform(
'In the second WebView, find an element that contains the message "This is a dummy webview."',
'In the second WebView, verify the headline has the message "This is a dummy webview."',
'Hide the second WebView',
'Show the 3rd WebView',
'There should be an iframe in the third WebView with the title "This is an iframe" or something similar'
Expand Down
5 changes: 0 additions & 5 deletions detox/test/e2e/copilot/05.system.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
const PromptHandler = require('./PromptHandler');
const {describeForCopilotEnv} = require("../utils/custom-describes");
const {expectToThrow} = require("../utils/custom-expects");

describeForCopilotEnv(':ios: iOS Permission Dialogs', () => {
beforeAll(async () => {
await copilot.init(new PromptHandler());
});

beforeEach(async () => {
await copilot.perform(
'Remove the app and start a fresh instance',
Expand Down
2 changes: 0 additions & 2 deletions detox/test/e2e/copilot/06.waitfor.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
const PromptHandler = require('./PromptHandler');
const {describeForCopilotEnv} = require("../utils/custom-describes");
const {expectToThrow} = require("../utils/custom-expects");

describeForCopilotEnv('WaitFor Functionality', () => {
beforeAll(async () => {
await copilot.init(new PromptHandler());
await copilot.perform('Launch the application');
});

Expand Down
118 changes: 0 additions & 118 deletions detox/test/e2e/copilot/PromptHandler.js

This file was deleted.

58 changes: 58 additions & 0 deletions detox/test/e2e/utils/PromptHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const axios = require('axios');
const fs = require('fs').promises;

class PromptHandler {
async uploadImage(imagePath) {
const image = await fs.readFile(imagePath);

try {
const response = await axios.post('https://bo.wix.com/mobile-infra-ai-services/v1/image-upload', {
image,
});

const imageUrl = response.data.url;
if (!imageUrl) {
throw new Error('Cannot find uploaded URL, got response:', response.data);
}

return imageUrl;
} catch (error) {
console.error('Error while uploading image:', error);
throw error;
}
}

async runPrompt(prompt, image) {
if (!image) {
throw new Error('Image is required');
}

const imageUrl = await this.uploadImage(image);

try {
const response = await axios.post('https://bo.wix.com/mobile-infra-ai-services/v1/prompt', {
prompt,
model: 'SONNET_3_5',
ownershipTag: 'Detox OSS',
project: 'Detox OSS',
images: [imageUrl]
});

const generatedText = response.data.generatedTexts[0];
if (!generatedText) {
throw new Error('Failed to generate text, got response:', response.data);
}

return generatedText;
} catch (error) {
console.error('Error running prompt:', error);
throw error;
}
}

isSnapshotImageSupported() {
return true;
}
}

module.exports = PromptHandler;
32 changes: 27 additions & 5 deletions detox/test/e2e/utils/custom-describes.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
// Custom describe functions to run tests only when Copilot is available on the environment
const axios = require('axios');
const PromptHandler = require("./PromptHandler");

const describeOrDescribeSkip = process.env.CI === 'true' ? describe.skip : describe;

describeForCopilotEnv = (description, fn) => {
if (process.env.COPILOT_IS_ENABLED === 'true') {
describe(description, fn);
} else {
describe.skip(description, fn);
describeOrDescribeSkip(':ios: Copilot', () => {
describe(description, () => {
beforeAll(async () => {
if (!await checkVpnStatus()) {
console.warn('Cannot access the LLM service without Wix BO environment. Relying on cached responses only.');
}

await copilot.init(new PromptHandler());
});

fn();
});
});
}

checkVpnStatus = async () => {
try {
const response = await axios.get('https://wix.wixanswers.com/_serverless/expert-toolkit/checkVpn');
return response.data.enabled === true;
} catch (error) {
console.error('Error checking VPN status:', error.message);
return false;
}
}

Expand Down
1 change: 0 additions & 1 deletion detox/test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
"cross-env": "^7.0.3",
"detox": "^20.27.3",
"detox-allure2-adapter": "^1.0.0-alpha.8",
"dotenv": "^16.4.5",
"eslint": "^8.56.0",
"eslint-plugin-unicorn": "^50.0.1",
"execa": "^5.1.1",
Expand Down
4 changes: 2 additions & 2 deletions detox/test/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default class example extends Component {
}

renderInlineSeparator() {
return <Text style={{width: 10}}> | </Text>;
return <Text style={{width: 30, color: 'gray', textAlign: 'center'}}> | </Text>;
}

renderMainMenu() {
Expand Down Expand Up @@ -120,7 +120,7 @@ export default class example extends Component {

<View style={{flexDirection: 'row', justifyContent: 'center'}}>
{this.renderScreenButton('Drag And Drop', Screens.DragNDropScreen)}
{isAndroid && this.renderInlineSeparator()}
{this.renderInlineSeparator()}
{this.renderScreenButton('Shape Match', Screens.ShapeMatchGameScreen)}
</View>

Expand Down

0 comments on commit e4705c3

Please sign in to comment.