Skip to content

Commit

Permalink
Video recorder (#13)
Browse files Browse the repository at this point in the history
* update to stage

* merge stage master

* initial update add support to video recorder and save to aws S3 bucket

* clean code

* update test
  • Loading branch information
resdenia authored Mar 2, 2023
1 parent 0908441 commit fe8a1b0
Show file tree
Hide file tree
Showing 22 changed files with 869 additions and 141 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ cloudFormation.zip
example-test-2.js
example-test.js
client/build
index-config-bkp.js
index-config-bkp.js
upload-test.js
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ COPY ./ ./

WORKDIR /usr/app/service/lambdaFunction

RUN npm install
RUN npm install --force
RUN npm install @ffmpeg-installer/linux-x64 --force

WORKDIR /usr/app/client

Expand Down
80 changes: 80 additions & 0 deletions client/src/components/Checkbox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { FunctionComponent } from 'react';
import Text from '../Text';

import styled from 'styled-components';

interface IProps {
title: string;
description: string;
onClick: () => void;
statusCheckbox: boolean;
}
const IconCheck = styled.svg`
display: none;
`;
const CheckboxContainer = styled.div`
display: flex;
margin-bottom: 15px;
`;
const CheckboxTextWrapper = styled.div`
margin-left: 10px;
h2 {
margin-bottom: 5px;
}
`;
const CheckboxWrapper = styled.div`
margin-top: 10px;
cursor: pointer;
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
width: 16px;
height: 16px;
border: 1px solid rgb(231, 231, 231);
border-radius: 2px;
transition: all 150ms ease 0s;
background-color: white;
outline: none;
align-self: flex-start;
&.active {
display: flex;
background: #5b78a4;
}
&.active svg {
display: flex;
}
`;

const Checkbox: FunctionComponent<IProps> = ({
title,
description,
statusCheckbox,
onClick,
}) => {
return (
<CheckboxContainer onClick={onClick}>
<CheckboxWrapper className={`${statusCheckbox ? 'active' : ''}`}>
<IconCheck
className='iconCheck'
width='10'
height='8'
viewBox='0 0 10 8'
fill='none'
>
<path
d='M3.58435 5.16434L8.29047 0.40882C8.47752 0.21893 8.70709 0.119856 8.97917 0.1116C9.25975 0.103344 9.49782 0.194161 9.69338 0.384052C9.88894 0.565686 9.99097 0.79273 9.99947 1.06518C10.008 1.32938 9.91444 1.55642 9.71889 1.74631L3.64812 7.88886L0.306644 4.8052C0.111087 4.62357 0.00905699 4.40065 0.000554509 4.13646C-0.00794797 3.864 0.081328 3.63283 0.268383 3.44294C0.46394 3.2448 0.697758 3.14572 0.969837 3.14572C1.24192 3.13747 1.47999 3.22416 1.68405 3.40579L3.58435 5.16434Z'
fill='white'
/>
</IconCheck>
</CheckboxWrapper>
<CheckboxTextWrapper>
<Text tag='h2'>{title}</Text>
<Text tag='p'>{description}</Text>
</CheckboxTextWrapper>
</CheckboxContainer>
);
};

export default Checkbox;
16 changes: 15 additions & 1 deletion client/src/containers/EditCodeContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import CodeEditor from '../../components/CodeEditor';
import EnvVariableContainer from '../EnvVariableContainer';
import Text from '../../components/Text';
import Select from '../../components/Select';

import Checkbox from '../../components/Checkbox';
import {
availableCodeLanguages,
platformDevice,
Expand Down Expand Up @@ -63,6 +63,7 @@ const MainWrapper = styled.div`
justify-content: space-between;
height: 75%;
`;
const RecordVideoWrapper = styled.div``;

const BottomWrapper = styled.div`
display: flex;
Expand Down Expand Up @@ -97,18 +98,22 @@ interface IProps {
uniqueKey: (isUnique: boolean) => void;
codeSnippet: string;
testDevice: string;
onChangeRecordStatus: boolean;
setCodeSnippet: (val: string) => void;
setEnvVariable: (envVariable: EnvVariable[]) => void;
setTestDevice: (val: string) => void;
onChangeRecord: () => void;
}

const EditCodeContainer: FunctionComponent<IProps> = ({
uniqueKey,
codeSnippet,
testDevice,
onChangeRecordStatus,
setCodeSnippet,
setEnvVariable,
setTestDevice,
onChangeRecord,
}) => {
const [codeLanguage, setCodeLanguage] = useState<string>('Playwright');
const [loading, setLoading] = useState<boolean>(false);
Expand Down Expand Up @@ -175,6 +180,14 @@ const EditCodeContainer: FunctionComponent<IProps> = ({
codeSnippet={codeSnippet}
/>
<SideWrapper>
<RecordVideoWrapper>
<Checkbox
title='Record video'
description='Record browser based video of the test'
onClick={onChangeRecord}
statusCheckbox={onChangeRecordStatus}
/>
</RecordVideoWrapper>
<Text tag='h2'>Select Device</Text>
<Text tag={'p'}>
Select the device on which you would like to execute
Expand All @@ -187,6 +200,7 @@ const EditCodeContainer: FunctionComponent<IProps> = ({
currentValue={testDevice}
/>
</SelectWrapperDevice>

<EnvVariableContainer
uniqueKey={uniqueKey}
onSetListEnvVariable={setEnvVariable}
Expand Down
9 changes: 8 additions & 1 deletion client/src/page/Home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const Home: FunctionComponent = () => {
});
const [codeSnippet, setCodeSnippet] = useState<string>(DEFAULT_CODE);
const [testDevice, setTestDevice] = useState<string>('Desktop Chrome');

const [onChangeRecordStatus, onChangeRecord] = useState<boolean>(false);
const [activeStep, setActiveStep] = useState<string>('edit_code');
const [stageDeploy, setStageDeploy] = useState<StatusProps>({
message: 'Function creating...',
Expand Down Expand Up @@ -132,6 +132,9 @@ const Home: FunctionComponent = () => {
const onDownload = (step: boolean) => {
setIsDownload(step);
};
const onChangeRecordHandler = () => {
onChangeRecord(!onChangeRecordStatus);
};

const [activeCloudProvider, setActiveCloudProvider] =
useState<string>('AWS');
Expand All @@ -158,6 +161,7 @@ const Home: FunctionComponent = () => {

response = await api.downloadCFTemplate(
codeSnippet,
onChangeRecordStatus,
testDevice,
envList,
configs.name.value,
Expand Down Expand Up @@ -198,6 +202,7 @@ const Home: FunctionComponent = () => {
rangeTimeVariable[
activeRangeTime.split(' ').reverse().join('_')
],
onChangeRecordStatus,
testDevice,
codeSnippet,
configs.name.value,
Expand Down Expand Up @@ -291,6 +296,8 @@ const Home: FunctionComponent = () => {
uniqueKey={uniqueEnvVariableHandler}
testDevice={testDevice}
codeSnippet={codeSnippet}
onChangeRecordStatus={onChangeRecordStatus}
onChangeRecord={onChangeRecordHandler}
setCodeSnippet={onSetCodeSnippetHandler}
setEnvVariable={onSetEnvVariableHandler}
setTestDevice={setTestDevice}
Expand Down
10 changes: 6 additions & 4 deletions client/src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class Api {
}
};

initPage = async (rangeTime: number, testDevice: string, codeSnippet: string, name: string, accessKey: string, secretKey: string, bucketName: string, token: string, listenerUrl: string, region: string, listEnvVariables: object, onStage: (stage: StatusProps) => void, description?: string) => {
initPage = async (rangeTime: number, onChangeRecordStatus: boolean, testDevice: string, codeSnippet: string, name: string, accessKey: string, secretKey: string, bucketName: string, token: string, listenerUrl: string, region: string, listEnvVariables: object, onStage: (stage: StatusProps) => void, description?: string) => {

const responseModify = await this.customFetch(
{ code: codeSnippet, testDevice },
Expand Down Expand Up @@ -174,7 +174,7 @@ class Api {
region,
listEnvVariables,
listenerUrl,

onChangeRecordStatus
},
settings.endPointUrls.createLambdaUrl,
);
Expand Down Expand Up @@ -226,7 +226,7 @@ class Api {
return cloudBridgeEventResp;
}
};
downloadCFTemplate = async (codeSnippet: string, testDevice: string, envList: object, name: string, rangeTime: number, bucket: string, token: string, region: string, listener: string, onDownload: (step: boolean) => void, description?: string) => {
downloadCFTemplate = async (codeSnippet: string, onChangeRecordStatus: boolean, testDevice: string, envList: object, name: string, rangeTime: number, bucket: string, token: string, region: string, listener: string, onDownload: (step: boolean) => void, description?: string) => {
onDownload(true)

const responseModify = await this.customFetch(
Expand All @@ -248,7 +248,9 @@ class Api {
bucket,
listener,
region,
rangeTime
rangeTime,
onChangeRecordStatus,
testDevice
},
settings.endPointUrls.createCfZip,
);
Expand Down
6 changes: 6 additions & 0 deletions controllers/creator.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ exports.createLambda = async (req, res) => {
region,
listEnvVariables,
listenerUrl,
onChangeRecordStatus,
} = req.body;
try {
const lambdaResp = await createLambda(
Expand All @@ -103,6 +104,7 @@ exports.createLambda = async (req, res) => {
region,
listEnvVariables,
listenerUrl,
onChangeRecordStatus,
);
if (lambdaResp.error) {
throw Error(lambdaResp.err);
Expand Down Expand Up @@ -180,6 +182,8 @@ exports.createZipCF = async (req, res) => {
listener,
region,
rangeTime,
onChangeRecordStatus,
testDevice,
} = req.body;

try {
Expand All @@ -192,6 +196,8 @@ exports.createZipCF = async (req, res) => {
listener,
region,
rangeTime,
onChangeRecordStatus,
testDevice,
);
await fileToZipCF(name);

Expand Down
43 changes: 32 additions & 11 deletions helper/index-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = {
const path = require('path');
const readSendData = require('./rsData');
const cfnResponse = require('cfn-response-async');
const { saveVideo } = require('playwright-video');
const pageHandler = require('./handlerHar');
const firstRun = async (event, context) => {
Expand All @@ -24,24 +25,31 @@ module.exports = {
let context = null;
let err = null;
let page = null;
let browser = null;
let capture;
let browser;
const visitedUrls= [];
try {
browser = await playwright.launchChromium(false);
browser = await playwright.launchChromium();
context = await browser.newContext({
...mobileDevice
});
await context.tracing.start({ screenshots: false, snapshots: false });
page = await context.newPage();
let count = 0;
page.on('load', async (data) => {
count++;
await pageHandler(data, count);
visitedUrls.push(data.url());
});
if(process.env.IS_RECORD === 'to_record'){
capture = await saveVideo(page, path.join(__dirname,'..', '..', 'tmp', 'video.mp4'));
}
`,
startFile: `const playwright = require('playwright-aws-lambda');
startFile: `
const { saveVideo } = require('playwright-video');
const playwright = require('playwright-aws-lambda');
const path = require('path');
const readSendData = require('./rsData');
const cfnResponse = require('cfn-response-async');
Expand All @@ -63,32 +71,43 @@ module.exports = {
let context = null;
let err = null;
let page = null;
let capture;
let browser;
const visitedUrls= [];
try {
browser = await playwright.launchChromium(false);
browser = await playwright.launchChromium();
context = await browser.newContext({
});
await context.tracing.start({ screenshots: false, snapshots: false });
page = await context.newPage();
let count = 0;
page.on('load', async (data) => {
count++;
await pageHandler(data, count);
visitedUrls.push(data.url());
});
if(process.env.IS_RECORD === 'to_record'){
capture = await saveVideo(page, path.join(__dirname,'..', '..', 'tmp', 'video.mp4'));
}
`,
endFile: `
} catch (error) {
console.log(error);
err = error.message;
} finally {
if (browser) {
await context.tracing.stop({
path: path.join(__dirname, '..', '..', 'tmp', 'trace.zip'),
});
if(process.env.IS_RECORD === 'to_record'){
await capture.stop();
}
await context.close();
await browser.close();
await pageHandler(visitedUrls);
}
}
await readSendData(err);
Expand Down Expand Up @@ -123,6 +142,7 @@ const handlerLocally = async () => {
`,
startFileLocally: `const playwright = require('playwright-aws-lambda');
const { chromium } = require('playwright-core');
const path = require('path');
const errorStatusHandler = require('./statusError');
Expand All @@ -131,7 +151,8 @@ const handlerLocally = async () => {
let err = null;
let page = null;
let browser = null;
try {
try {
browser = await chromium.launch({});
context = await browser.newContext();
page = await context.newPage();
Expand Down
Loading

0 comments on commit fe8a1b0

Please sign in to comment.