diff --git a/cypress/integration/sasjs.tests.ts b/cypress/integration/sasjs.tests.ts index 43d6d37..e999de7 100644 --- a/cypress/integration/sasjs.tests.ts +++ b/cypress/integration/sasjs.tests.ts @@ -14,15 +14,23 @@ context('sasjs-tests', function () { function loginIfNeeded() { cy.get('body').then(($body) => { - if ($body.find('input[placeholder="User Name"]').length > 0) { - cy.get('input[placeholder="User Name"]') + if ($body.find('login-form').length > 0) { + cy.get('login-form') + .shadow() + .find('#username') .should('be.visible') .type(username) - cy.get('input[placeholder="Password"]') + cy.get('login-form') + .shadow() + .find('#password') .should('be.visible') .type(password) - cy.get('.submit-button').should('be.visible').click() - cy.get('input[placeholder="User Name"]').should('not.exist') // Wait for login to finish + cy.get('login-form') + .shadow() + .find('#submit-btn') + .should('be.visible') + .click() + cy.get('login-form').should('not.exist') // Wait for login to finish } }) } @@ -30,30 +38,36 @@ context('sasjs-tests', function () { it('Should have all tests successful', () => { loginIfNeeded() - cy.get('.ui.massive.icon.primary.left.labeled.button') - .should('be.visible') - .click() + cy.get('tests-view').shadow().find('#run-btn').should('be.visible').click() - cy.get('.ui.massive.loading.primary.button', { - timeout: testingFinishTimeout - }).should('not.exist') + cy.get('tests-view') + .shadow() + .find('#run-btn:disabled', { + timeout: testingFinishTimeout + }) + .should('not.exist') - cy.get('span.icon.failed').should('not.exist') + cy.get('test-card').shadow().find('.status-icon.failed').should('not.exist') }) it('Should have all tests successful with debug on', () => { loginIfNeeded() - cy.get('.ui.fitted.toggle.checkbox label').should('be.visible').click() - - cy.get('.ui.massive.icon.primary.left.labeled.button') + cy.get('tests-view') + .shadow() + .find('#debug-toggle') .should('be.visible') .click() - cy.get('.ui.massive.loading.primary.button', { - timeout: testingFinishTimeout - }).should('not.exist') + cy.get('tests-view').shadow().find('#run-btn').should('be.visible').click() - cy.get('span.icon.failed').should('not.exist') + cy.get('tests-view') + .shadow() + .find('#run-btn:disabled', { + timeout: testingFinishTimeout + }) + .should('not.exist') + + cy.get('test-card').shadow().find('.status-icon.failed').should('not.exist') }) }) diff --git a/sasjs-tests/.env b/sasjs-tests/.env deleted file mode 100644 index fba2a35..0000000 --- a/sasjs-tests/.env +++ /dev/null @@ -1,3 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -# Removes index.html inline scripts -INLINE_RUNTIME_CHUNK=false diff --git a/sasjs-tests/.gitignore b/sasjs-tests/.gitignore index 0da9af7..fe66985 100644 --- a/sasjs-tests/.gitignore +++ b/sasjs-tests/.gitignore @@ -1,23 +1,29 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.* - +# Logs +logs +*.log npm-debug.log* yarn-debug.log* yarn-error.log* +pnpm-debug.log* +lerna-debug.log* +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + + +# sasjs sasjsbuild sasjsresults \ No newline at end of file diff --git a/sasjs-tests/.prettierrc b/sasjs-tests/.prettierrc deleted file mode 100644 index c50384f..0000000 --- a/sasjs-tests/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "trailingComma": "none", - "tabWidth": 2, - "semi": false, - "singleQuote": true -} diff --git a/sasjs-tests/README.md b/sasjs-tests/README.md index cebec2c..54c6c61 100644 --- a/sasjs-tests/README.md +++ b/sasjs-tests/README.md @@ -1,6 +1,8 @@ +# SASjs Tests + `sasjs-tests` is a test suite for the SASjs adapter. -It is a React app bootstrapped using [Create React App](https://github.com/facebook/create-react-app) and [@sasjs/test-framework](https://github.com/sasjs/test-framework). +Browser-based integration testing for [@sasjs/adapter](https://github.com/sasjs/adapter) using TypeScript, Custom Elements, and zero dependencies. When developing on `@sasjs/adapter`, it's good practice to run the test suite against your changed version of the adapter to ensure that existing functionality has not been impacted. @@ -20,43 +22,122 @@ There are three prerequisites to be able to run the tests: 2. `sasjs-tests` deployed to your SAS server. 3. The required SAS services created on the same server. -### 1. Configuring the SASjs adapter +### Configuring the SASjs adapter There is a `config.json` file in the `/public` folder which specifies the configuration for the SASjs adapter. You can set the values within the `sasjsConfig` property in this file to match your SAS server configuration. -### 2. Deploying to your SAS server - -There is a `deploy` NPM script provided in the `sasjs-tests` project's `package.json`. - -It updates `sasjs-tests` to use the latest version of the adapter, and deploys to a specified server via SSH using the `rsync` command. - -To be able to run the `deploy` script, two environment variables need to be set: - -- `SSH_ACCOUNT` - your SSH account, this is of the form username@domain.com -- `DEPLOY_PATH` - the path on the server where `sasjs-tests` will be deployed to, typically `/var/www/html/`. - -So you can run the script like so: +#### Installation ```bash -SSH_ACCOUNT=me@my-sas-server.com DEPLOY_PATH=/var/www/html/my-folder/sasjs-tests npm run deploy +npm install ``` -If you are on `WINDOWS`, you will first need to install one dependency: -```bash -npm i -g copyfiles -``` -and then run to build: -```bash -npm run update:adapter && npm run build -``` -when it finishes run to deploy: -```bash -scp -rp ./build/* me@my-sas-server.com:/var/www/html/my-folder/sasjs-tests +#### Configuration + +Edit `public/config.json`: + +```json +{ + "userName": "your-username", + "password": "your-password", + "sasJsConfig": { + "serverUrl": "https://your-sas-server.com", + "appLoc": "/Public/app/adapter-tests/services", + "serverType": "SASJS", + "debug": false, + "contextName": "sasjs adapter compute context", + "useComputeApi": true + } +} ``` -If you'd like to deploy just `sasjs-tests` without changing the adapter version, you can use the `deploy:tests` script, while also setting the same environment variables as above. +**Server Types:** -## 3. Creating the required SAS services +- `SASJS` - SASjs Server +- `SASVIYA` - SAS Viya +- `SAS9` - SAS 9.4 + +## Getting Started + +### Development + +```bash +# Build for production +npm run build + +# Watch mode (rebuild on changes) +npm run dev +``` + +The built files are in `build/`: + +- `index.html` - App entry point +- `index.js` - Bundled JavaScript +- `index.css` - Global styles +- `config.json` - Configuration + +## Test Suites + +Tests are defined in `src/testSuites/`: + +- **Basic.ts** - Login, config, session management, debug mode +- **RequestData.ts** - Data serialization (sendArr, sendObj) with various types +- **FileUpload.ts** - File upload functionality (VIYA only) +- **Compute.ts** - Compute API, JES API, executeScript (VIYA only) +- **SasjsRequests.ts** - WORK tables, log capture +- **SpecialCases.ts** - Edge cases (currently disabled) + +Each test suite follows this pattern: + +```typescript +export const myTests = (adapter: SASjs): TestSuite => ({ + name: 'My Test Suite', + tests: [ + { + title: 'Should do something', + description: 'Description of what this tests', + test: async () => { + // Test logic - return a value + return adapter.request('service', data) + }, + assertion: (response) => { + // Assertion - return true/false + return response.success === true + } + } + ], + beforeAll: async () => { + // Optional: runs once before all tests + }, + afterAll: async () => { + // Optional: runs once after all tests + } +}) +``` + +### Shadow DOM Access + +Cypress accesses Shadow DOM using a custom command: + +```javascript +cy.get('login-form').shadow().find('input#username').type('user') +``` + +The `shadow()` command is defined in `cypress/support/commands.js`. + +## Deployment + +### Build for Production + +```bash +npm run build +``` + +This creates a `build/` folder ready for deployment. + +### Deploy to SAS Server + +#### Creating the required SAS services The below services need to be created on your SAS server, at the location specified as the `appLoc` in the SASjs configuration. @@ -75,8 +156,8 @@ parmcards4; %let table=%scan(&sasjs_tables,&i); %webout(OBJ,&table,missing=STRING,showmeta=YES) %end; - %else %do i=1 %to &_webin_file_count; - %webout(OBJ,&&_webin_name&i,missing=STRING,showmeta=YES) + %else %do i=1 %to &_webin_file_count; + %webout(OBJ,&&_webin_name&i,missing=STRING,showmeta=YES) %end; %mend; %x() %webout(CLOSE) @@ -90,8 +171,8 @@ parmcards4; %let table=%scan(&sasjs_tables,&i); %webout(ARR,&table,missing=STRING,showmeta=YES) %end; - %else %do i=1 %to &_webin_file_count; - %webout(ARR,&&_webin_name&i,missing=STRING,showmeta=YES) + %else %do i=1 %to &_webin_file_count; + %webout(ARR,&&_webin_name&i,missing=STRING,showmeta=YES) %end; %mend; %x() %webout(CLOSE) @@ -102,7 +183,7 @@ parmcards4; set sashelp.vmacro; run; %webout(OPEN) - %webout(OBJ,macvars) + %webout(OBJ,macvars) %webout(CLOSE) ;;;; %mx_createwebservice(path=&apploc/services/common,name=sendMacVars) @@ -126,23 +207,100 @@ data _null_; You should now be able to access the tests in your browser at the deployed path on your server. -## Creating new tests +#### Using SASjs CLI -The `src/testSuites` folder contains all the test suites currently available. -Each suite contains a set of specs, each of which looks like this: - -```javascript - { - title: "Your test title", - description: "A slightly more detailed description", - test: async () => { - // typically makes a request using the adapter and returns a promise - }, - assertion: (response: any) => - // receives the response when the test promise resolves, runs an assertion and returns a boolean - } +```bash +sasjs deploy -t ``` -A test suite is an array of such objects, along with a `name` property. +### Matrix Notifications -You can add your test to one of the existing suites if suitable, or create a new file that specifies a new test suite. +The `sasjs-cypress-run.sh` script sends Matrix chat notifications on test failure: + +```bash +./sasjs-cypress-run.sh $MATRIX_ACCESS_TOKEN $PR_NUMBER +``` + +Notification format: + +``` +Automated sasjs-tests failed on the @sasjs/adapter PR: +``` + +## SAS Service Setup + +The tests require SAS services to be deployed at the `appLoc` specified in `config.json`. + +Services expected: + +- `common/sendArr` - Echo back array data +- `common/sendObj` - Echo back object data +- (Additional services per test suite) + +Deploy these services using [SASjs CLI](https://cli.sasjs.io) or manually. + +## Troubleshooting + +### Build Errors + +- Ensure Node.js >= 18 +- Clear `node_modules` and reinstall: `rm -rf node_modules package-lock.json && npm install` + +### Cypress Shadow DOM Issues + +If Cypress can't access Shadow DOM elements: + +1. Verify custom `shadow()` command in `cypress/support/commands.js` +2. Check element selectors match actual DOM structure + +### Test Failures + +- Check `config.json` credentials and server URL +- Verify SAS services are deployed +- Check browser console for errors +- Enable `debug: true` in sasJsConfig for verbose logging + +## Development + +- **Pure Vanilla TS** - No React, no frameworks +- **Custom Elements** - Web Components with Shadow DOM +- **Zero Dependencies** - Only @sasjs/adapter + build tools +- **Minimal Bundle** - 40KB (8KB gzipped) + +### Build Stack + +- **tsdown** - TypeScript bundler (replaces CRA/react-scripts) + +### UI Components (Custom Elements) + +- `` - SAS authentication +- `` - Test orchestrator with run controls +- `` - Test suite display with stats +- `` - Individual test with status (pending/running/passed/failed) + +All components use Shadow DOM for style encapsulation and expose custom events for interactivity. + +### Adding New Test Suites + +1. Create file in `src/testSuites/MyNewTests.ts` +2. Export function returning TestSuite +3. Import in `src/index.ts` +4. Add to `testSuites` array in `showTests()` function + +### Modifying UI Components + +Components are in `src/components/`: + +- Edit `.ts` file +- Styles are in Shadow DOM `