Skip to content

Commit

Permalink
feat: add Cypress (#1094)
Browse files Browse the repository at this point in the history
Co-authored-by: Khuda Dad Nomani <[email protected]>
  • Loading branch information
aeworxet and KhudaDad414 authored Sep 17, 2024
1 parent 4fec902 commit 41365d4
Show file tree
Hide file tree
Showing 29 changed files with 4,982 additions and 4,169 deletions.
4 changes: 0 additions & 4 deletions .dockerignore

This file was deleted.

4 changes: 2 additions & 2 deletions .sonarcloud.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Disable specific file since it would introduce more complexity to reduce it - mainly code complexity and complex template literals
sonar.exclusions=apps/studio/public/js/monaco/**,apps/studio/src/tailwind.css,apps/studio/src/components/SplitPane/**
sonar.exclusions=apps/studio/public/js/monaco/**,apps/studio/src/tailwind.css,apps/studio/src/components/SplitPane/**,apps/studio-next/cypress/**,apps/studio-next/Dockerfile
# Disable duplicate code in tests since it would introduce more complexity to reduce it.
sonar.cpd.exclusions=apps/studio/**,apps/studio-next/src/components/Navigationv3.tsx,apps/studio-next/src/components/Navigation.tsx
sonar.cpd.exclusions=apps/studio/**,apps/studio-next/src/components/Navigationv3.tsx,apps/studio-next/src/components/Navigation.tsx,apps/studio-next/cypress/**
9 changes: 9 additions & 0 deletions apps/studio-next/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"env": {
"es6": true,
"browser": true,
"node": true
},
"plugins": ["security"],
"extends":["eslint-config-custom", "eslint-config-custom/react"]
}
11 changes: 11 additions & 0 deletions apps/studio-next/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineConfig } from 'cypress';

export default defineConfig({
e2e: {
baseUrl: 'http://localhost:3001',
retries: {
runMode: 1,
openMode: 1,
},
},
});
136 changes: 136 additions & 0 deletions apps/studio-next/cypress/e2e/studio-ui.spec.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// import { isV3 } from "../../src/components/Sidebar";
const isV3Test = true;

/* Testing commented hovers is impossible even with `cypress-real-events` so
testing of these hovers is postponed until either Cypress has better support for
`mouseover`/`mouseenter` events or the architecture of `Studio` is changed to
allow testing those. */

describe('Studio UI spec', () => {
beforeEach(() => {
cy.visit('/');
});

it('Logo should be visible in the UI', () => {
cy.get('[data-test="logo"]').should('be.visible');
});

// it('Logo should display tooltip "AsyncAPI Logo" on hover', () => {
// cy.get('[data-test="logo"]').trigger('mouseenter');
// cy.contains('AsyncAPI Logo').should('be.visible');
// });

it('Button "AsyncAPI Website" should be visible in the UI', () => {
cy.get('[data-test="button-website"]').should('be.visible');
});

// it('Button "AsyncAPI Website" should display tooltip "AsyncAPI Website" on hover', () => {
// cy.get('[data-test="button-website"]').trigger('mouseenter');
// cy.contains('AsyncAPI Website').should('be.visible');
// });

it('Button "AsyncAPI Github Organization" should be visible in the UI', () => {
cy.get('[data-test="button-github"]').should('be.visible');
});

// it('Button "AsyncAPI Github Organization" should display tooltip "AsyncAPI Github Organization" on hover', () => {
// cy.get('[data-test="button-github"]').trigger('mouseenter');
// cy.contains('AsyncAPI Github Organization').should('be.visible');
// });

it('Button "AsyncAPI Slack Workspace" should be visible in the UI', () => {
cy.get('[data-test="button-slack"]').should('be.visible');
});

// it('Button "AsyncAPI Slack Workspace" should display tooltip "AsyncAPI Slack Workspace" on hover', () => {
// cy.get('[data-test="button-slack"]').trigger('mouseenter');
// cy.contains('AsyncAPI Slack Workspace').should('be.visible');
// });

it('Button "Navigation" should be visible in the UI', () => {
cy.get('[data-test="button-navigation"]').should('be.visible');
});

it('Button "Navigation" should display tooltip "Navigation" on hover', () => {
cy.get('[data-test="button-navigation"]').trigger('mouseenter');
cy.contains('Navigation').should('be.visible');
});

it('Button "Editor" should be visible in the UI', () => {
cy.get('[data-test="button-editor"]').should('be.visible');
});

it('Button "Editor" should display tooltip "Editor" on hover', () => {
cy.get('[data-test="button-editor"]').trigger('mouseenter');
cy.contains('Editor').should('be.visible');
});

it('Button "Template preview" should be visible in the UI', () => {
cy.get('[data-test="button-template-preview"]').should('be.visible');
});

it('Button "Template preview" should display tooltip "Template preview" on hover', () => {
cy.get('[data-test="button-template-preview"]').trigger('mouseenter');
cy.contains('Template preview').should('be.visible');
});

if (!isV3Test) { // review the need of v2 testing in general
it('Button "Blocks visualiser" should be visible in the UI', () => {
cy.get('[data-test="button-blocks-visualiser"]').should('be.visible');
});

it('Button "Blocks visualiser" should display tooltip "Blocks visualiser" on hover', () => {
cy.get('[data-test="button-blocks-visualiser"]').trigger('mouseenter');
cy.contains('Blocks visualiser').should('be.visible');
});
}

it('Button "New file" should be visible in the UI', () => {
cy.get('[data-test="button-new-file"]').should('be.visible');
});

it('Button "New file" should display tooltip "New file" on hover', () => {
cy.get('[data-test="button-new-file"]').trigger('mouseenter');
cy.contains('New file').should('be.visible');
});

it('Button "Settings" should be visible in the UI', () => {
cy.get('[data-test="button-settings"]').should('be.visible');
});

it('Button "Settings" should display tooltip "Studio settings" on hover', () => {
cy.get('[data-test="button-settings"]').trigger('mouseenter');
cy.contains('Studio settings').should('be.visible');
});

it('Button "Share" should be visible in the UI', () => {
cy.get('[data-test="button-share"]').should('be.visible');
});

it('Button "Share" should display tooltip "Share link" on hover', () => {
cy.get('[data-test="button-share"]').trigger('mouseenter');
cy.contains('Share link').should('be.visible');
});

it('Button "Dropdown" should be visible in the UI', () => {
cy.get('[data-test="button-dropdown"]').should('be.visible');
});

it('Dropdown menu should contain 8 elements with predefined text', () => {
cy.get('[data-test="button-dropdown"]').click();
cy.contains('Import from URL');
cy.contains('Import File');
cy.contains('Import from Base64');
cy.contains('Generate code/docs');
cy.contains('Save as YAML');
cy.contains('Convert and save as JSON');
cy.contains('Convert to JSON');
cy.contains('Convert document');
});

it('Click on Dropdown menu\'s element "Generate code/docs" should open Modal window "Generate code/docs based on your AsyncAPI Document"', () => {
cy.get('[data-test="button-dropdown"]').click();
cy.contains('Generate code/docs').click();
cy.contains('Generate code/docs based on your AsyncAPI Document');
});
});
5 changes: 5 additions & 0 deletions apps/studio-next/cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "[email protected]",
"body": "Fixtures are a great way to mock data for responses to routes"
}
37 changes: 37 additions & 0 deletions apps/studio-next/cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
20 changes: 20 additions & 0 deletions apps/studio-next/cypress/support/e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands'

// Alternatively you can use CommonJS syntax:
// require('./commands')
13 changes: 7 additions & 6 deletions apps/studio-next/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ const nextConfig = {
config.module.rules.push({
test: /\.yml$/i,
type: 'asset/source',
})
});

if (isServer) return config
if (isServer) return config;
// Important: return the modified config
config.resolve.fallback = {
...config.resolve.fallback,
Expand All @@ -25,7 +25,7 @@ const nextConfig = {
debug: false,
canvas: false,
fs: false,
}
};

config.plugins.push(
new webpack.ProvidePlugin({
Expand All @@ -34,8 +34,9 @@ const nextConfig = {
})
);

return config
return config;
},
}
output: 'standalone'
};

module.exports = nextConfig
module.exports = nextConfig;
16 changes: 11 additions & 5 deletions apps/studio-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start",
"lint": "echo 'No linting configured'"
"lint": "next lint",
"cy:e2e:chrome": "cypress run --e2e --browser chrome",
"cy:e2e:chromium": "cypress run --e2e --browser chromium",
"cy:e2e:edge": "cypress run --e2e --browser edge",
"cy:e2e:electron": "cypress run --e2e --browser electron",
"cy:e2e:firefox": "cypress run --e2e --browser firefox",
"cy:open": "cypress open"
},
"dependencies": {
"@asyncapi/avro-schema-parser": "^3.0.19",
"@asyncapi/converter": "^1.4.16",
"@asyncapi/converter": "^1.6.0",
"@asyncapi/openapi-schema-parser": "^3.0.18",
"@asyncapi/parser": "^3.2.2",
"@asyncapi/protobuf-schema-parser": "^3.2.8",
Expand All @@ -30,12 +36,10 @@
"react-icons": "^4.6.0",
"reactflow": "^11.2.0",
"@stoplight/yaml": "^4.3.0",
"@codemirror/view": "^6.26.3",
"@types/node": "20.4.6",
"@types/react": "18.2.18",
"@types/react-dom": "18.2.7",
"autoprefixer": "10.4.14",
"codemirror": "^6.0.1",
"eslint-config-next": "13.4.12",
"next": "14.2.3",
"postcss": "8.4.31",
Expand Down Expand Up @@ -72,6 +76,7 @@
"autoprefixer": "^10.4.13",
"browserify-zlib": "^0.2.0",
"buffer": "^6.0.3",
"cypress": "^13.10.0",
"eslint-config-next": "14.1.4",
"eslint-plugin-security": "^1.5.0",
"eslint-plugin-sonarjs": "^0.16.0",
Expand All @@ -88,5 +93,6 @@
"util": "^0.12.5",
"web-vitals": "^3.1.0",
"webpack": "^5.75.0"
}
},
"packageManager": "[email protected]"
}
8 changes: 5 additions & 3 deletions apps/studio-next/scripts/template-parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import { JSONSchema7 } from 'json-schema';

const DESTINATION_JSON = path.join(__dirname, '../src/components/Modals/Generator/template-parameters.json');
const TEMPLATES: Record<string, string> = {
'@asyncapi/dotnet-nats-template': '.NET Nats Project',
'@asyncapi/dotnet-nats-template': '.NET NATS Project',
'@asyncapi/dotnet-rabbitmq-template': '.NET C# RabbitMQ Project',
'@asyncapi/go-watermill-template': 'GO Lang Watermill Project',
'@asyncapi/html-template': 'HTML website',
'@asyncapi/java-spring-cloud-stream-template': 'Java Spring Cloud Stream Project',
'@asyncapi/java-spring-template': 'Java Spring Project',
'@asyncapi/java-template': 'Java Project',
'@asyncapi/markdown-template': 'Markdown Documentation',
'@asyncapi/nodejs-template': 'NodeJS Project',
'@asyncapi/nodejs-ws-template': 'NodeJS WebSocket Project',
'@asyncapi/nodejs-ws-template': 'NodeJS WebSocket Projects',
'@asyncapi/php-template': 'PHP RabbitMQ Project',
'@asyncapi/python-paho-template': 'Python Paho Project',
'@asyncapi/ts-nats-template': 'Typescript Nats Project',
'@asyncapi/ts-nats-template': 'Typescript NATS Project',
};
const SUPPORTED_TEMPLATES = Object.keys(TEMPLATES);

Expand Down
6 changes: 6 additions & 0 deletions apps/studio-next/src/app/api/v1/generate/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
const response = await request.json();
return new NextResponse(`route POST -> ${JSON.stringify(response)}`, {status: 201});
}
4 changes: 2 additions & 2 deletions apps/studio-next/src/components/Editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ export const Editor: React.FunctionComponent<EditorProps> = () => {
const editorHeight = useOtherState(state => state.editorHeight);

return (
<div className="flex flex-1 overflow-hidden">
<div className="flex flex-1">
<SplitPane
split="horizontal"
minSize={29}
maxSize={-36}
size={editorHeight}
defaultSize={editorHeight}
>
<div className="flex flex-1 flex-col h-full overflow-hidden">
<div className="flex flex-1 flex-col h-full">
<EditorSidebar />
<MonacoWrapper />
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/studio-next/src/components/Editor/ShareButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const ShareButton: React.FunctionComponent<ShareButtonProps> = () => {

return (
<Tooltip content={'Share link'} placement="top" hideOnClick={true}>
<button className="bg-inherit" onClick={handleShare}>
<button className="bg-inherit" onClick={handleShare} data-test="button-share">
<FaShareAlt className="text-gray-500 hover:text-white" />
</button>
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ import templates from './template-parameters.json';

const unsupportedGenerators = [
'@asyncapi/dotnet-nats-template',
'@asyncapi/ts-nats-template',
'@asyncapi/python-paho-template',
'@asyncapi/nodejs-ws-template',
'@asyncapi/java-spring-cloud-stream-template',
'@asyncapi/go-watermill-template',
'@asyncapi/java-spring-cloud-stream-template',
'@asyncapi/java-spring-template',
'@asyncapi/nodejs-template',
'@asyncapi/java-template',
'@asyncapi/php-template'
'@asyncapi/nodejs-ws-template',
'@asyncapi/php-template',
'@asyncapi/python-paho-template',
'@asyncapi/ts-nats-template',
];

const renderOptions = (actualVersion: string) => {
Expand Down
Loading

0 comments on commit 41365d4

Please sign in to comment.