Skip to content

Commit 83dafea

Browse files
authored
Merge pull request #102 from contentstack/staging
Staging
2 parents c498588 + 38e763e commit 83dafea

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+5277
-16956
lines changed

.env.sample

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ BASIC_AUTH_PASSWORD = #Add your basic auth password
1717
# Based on the env make sure to add proper credentials for the below variables
1818
DEVELOPER_HUB_API= #Add Developer Hub API endpoint (e.g: developerhub-api.contentstack.com)
1919
ENV_URL= #Add App host URL (e.g: https://app.contentstack.com/)
20-
BASE_API_URL= #Add API end point (e.g: api.contentstack.io)
20+
BASE_API_URL= #Add API end point (e.g: api.contentstack.io)
21+
22+
VITE_PUBLIC_KEY_BASE_URL = #Add Vite public key base URL (e.g: https://app.contentstack.com)

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# dependencies
22
node_modules
33
playwright-report
4-
.env
4+
.env
5+
dist/
6+

e2e/pages/AssetPage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class AssetPage {
4141
await this.navigateToAsset(assetId);
4242
await this.widgetSelector();
4343
const frame = await this.accessFrame();
44-
await frame?.waitForSelector('.app-component-content');
44+
await frame?.waitForSelector('.ui-container');
4545
const locateText: any = await frame?.locator('text="Asset Sidebar Widget"');
4646
const matchText = await locateText?.innerText();
4747
expect(matchText).toBe('Asset Sidebar Widget');

e2e/pages/EntryPage.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class EntryPage {
4545
// Check for dashboard widget
4646
async validateDashboardWidget() {
4747
const frame = await this.accessFrame();
48-
await frame?.waitForSelector('.app-component-content');
48+
await frame?.waitForSelector('.ui-container');
4949
const locateText: any = await frame?.locator('text="Dashboard Widget"');
5050
const matchText = await locateText?.innerText();
5151
expect(matchText).toBe('Dashboard Widget');
@@ -54,12 +54,19 @@ export class EntryPage {
5454
// Check for entry custom field & entry side bar
5555
async validateCustomField() {
5656
const frame = await this.accessFrame();
57-
await frame?.waitForSelector('.custom-field-container');
57+
await frame?.waitForSelector('.ui-container');
5858
const locateText = await frame?.locator("text='Custom Field'");
5959
const matchText = await locateText?.innerText();
6060
expect(matchText).toBe('Custom Field');
6161
await this.widgetSelector();
6262
const sideBarWidget = await frame?.locator('.entry-sidebar-container >> text=Sidebar Widget');
6363
expect(sideBarWidget).toBeTruthy();
6464
}
65+
66+
async validateCustomFieldWithInvalidJWTToken() {
67+
const frame = await this.accessFrame();
68+
await frame?.waitForSelector('.app-failed-container');
69+
const locateText = await frame?.locator("text='The App was loaded outside Contentstack Dashboard.'");
70+
return locateText?.isVisible();
71+
}
6572
}

e2e/tests/app-flow.spec.ts

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { test} from '@playwright/test';
1+
import { test, expect} from '@playwright/test';
22
import { AssetPage } from '../pages/AssetPage';
33

4-
import { createContentType, createEntry, createApp, updateApp, installApp, assetUpload, uninstallApp, deleteApp, deleteContentType, entryPageFlow, initializeEntry, getExtensionFieldUid, deleteAsset } from '../utils/helper';
4+
import { createContentType, createEntry, createApp, updateApp, installApp, assetUpload, uninstallApp, deleteApp, deleteContentType, entryPageFlow, initializeEntry, getExtensionFieldUid, deleteAsset, mockFetchPublicKey } from '../utils/helper';
55

66
const jsonFile = require('jsonfile');
77

@@ -61,20 +61,53 @@ test.afterAll(async () => {
6161
}
6262
});
6363

64-
test('#1 Validate Dashboard Widget', async ({ page, context }) => {
64+
test('Verify Dashboard Widget', async ({ page, context }) => {
6565
const entryPage = await initializeEntry(page);
6666
await entryPage.navigateToDashboard();
6767
await entryPage.validateDashboardWidget();
6868
});
6969

70-
test('#2 Validating Custom Field & Entry Sidebar', async ({ page, context }) => {
70+
test('Verify Custom Field & Entry Sidebar', async ({ page, context }) => {
7171
const entryPage = await initializeEntry(page);
7272
await entryPageFlow(savedCredentials, entryPage);
7373
await entryPage.validateCustomField();
7474
});
7575

76-
test('#3 Validate Asset Sidebar', async ({ page, context }) => {
76+
test('Verify Asset Sidebar', async ({ page, context }) => {
7777
const { assetId } = savedCredentials;
7878
const assetPage = new AssetPage(page);
7979
await assetPage.validateAssetSideBar(assetId);
8080
});
81+
82+
test.skip("Verify if custom-field is loading for valid AppToken", async ({ page, context }) => {
83+
const entryPage = await initializeEntry(page);
84+
await entryPageFlow(savedCredentials, entryPage);
85+
await mockFetchPublicKey(context, true);
86+
87+
// Mocking a valid token
88+
await page.evaluate(() => {
89+
window.localStorage.setItem("app_token", "VALID_JWT_TOKEN");
90+
});
91+
92+
await page.reload();
93+
94+
// Expect the validateCustomField function to be called
95+
await entryPage.validateCustomField();
96+
});
97+
98+
test("Verify if AppFailed component is displayed for Invalid AppToken", async ({ page, context }) => {
99+
const entryPage = await initializeEntry(page);
100+
await entryPageFlow(savedCredentials, entryPage);
101+
await mockFetchPublicKey(context, false);
102+
103+
// Mocking an invalid token
104+
await page.evaluate(() => {
105+
window.localStorage.setItem("app_token", "INVALID_JWT_TOKEN");
106+
});
107+
108+
await page.reload();
109+
110+
// Expect the AppFailed component to be visible
111+
const isErrorDisplayed = await entryPage.validateCustomFieldWithInvalidJWTToken();
112+
expect(isErrorDisplayed).toBeTruthy();
113+
});

e2e/utils/helper.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ export const updateApp = async (authToken: string, appId: string) => {
195195
{
196196
name: `App Boilerplate _${Math.floor(Math.random() * 1000)}`,
197197
path: '/custom-field',
198-
signed: false,
198+
signed: true,
199199
enabled: true,
200200
data_type: 'text',
201201
},
@@ -424,3 +424,13 @@ export const getExtensionFieldUid = async (authToken: string) => {
424424
console.error(error);
425425
}
426426
};
427+
428+
// Utility function to mock valid and invalid app-tokens for signed requests
429+
export const mockFetchPublicKey = async (context, isValid = true) => {
430+
await context.route("**/.well-known/public-keys.json", (route) => {
431+
route.fulfill({
432+
status: 200,
433+
body: JSON.stringify({ "signing-key": isValid ? "VALID_PUBLIC_KEY_PEM" : "" }),
434+
});
435+
});
436+
};

index.html

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" type="image/svg+xml" href="/default-app-icon.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<meta name="theme-color" content="#000000" />
8+
<meta name="description" content="Marketplace App Boilerplate" />
9+
<link rel="apple-touch-icon" href="/logo192.png" />
10+
<link rel="manifest" href="/manifest.json" />
11+
<title>ContentStack Marketplace Boilerplate</title>
12+
</head>
13+
<body>
14+
<noscript>You need to enable JavaScript to run this app.</noscript>
15+
<div id="root"></div>
16+
<script type="module" src="/src/main.tsx"></script>
17+
</body>
18+
</html>

manifest.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"meta": [
1616
{
1717
"multiple": false,
18-
"path": "/#/custom-field",
18+
"path": "/custom-field",
1919
"signed": false,
2020
"enabled": true,
2121
"data_type": "json"
@@ -26,7 +26,7 @@
2626
"type": "cs.cm.stack.dashboard",
2727
"meta": [
2828
{
29-
"path": "/#/stack-dashboard",
29+
"path": "/stack-dashboard",
3030
"signed": false,
3131
"enabled": true,
3232
"default_width": "half"
@@ -38,7 +38,7 @@
3838
"meta": [
3939
{
4040
"blur": false,
41-
"path": "/#/asset-sidebar",
41+
"path": "/asset-sidebar",
4242
"signed": false,
4343
"enabled": true,
4444
"width": 500
@@ -49,7 +49,7 @@
4949
"type": "cs.cm.stack.content_type_sidebar",
5050
"meta": [
5151
{
52-
"path": "/#/content-type-sidebar",
52+
"path": "/content-type-sidebar",
5353
"signed": false,
5454
"enabled": true
5555
}
@@ -59,7 +59,7 @@
5959
"type": "cs.cm.stack.sidebar",
6060
"meta": [
6161
{
62-
"path": "/#/entry-sidebar",
62+
"path": "/entry-sidebar",
6363
"signed": false,
6464
"enabled": true
6565
}
@@ -69,7 +69,7 @@
6969
"type": "cs.cm.stack.full_page",
7070
"meta": [
7171
{
72-
"path": "/#/full-page",
72+
"path": "/full-page",
7373
"signed": false,
7474
"enabled": true
7575
}
@@ -79,7 +79,7 @@
7979
"type": "cs.cm.stack.field_modifier",
8080
"meta": [
8181
{
82-
"path": "/#/field-modifier",
82+
"path": "/field-modifier",
8383
"signed": false,
8484
"enabled": true,
8585
"allowed_types": ["$all"]
@@ -90,7 +90,7 @@
9090
"type": "cs.cm.stack.config",
9191
"meta": [
9292
{
93-
"path": "/#/app-configuration",
93+
"path": "/app-configuration",
9494
"signed": false,
9595
"enabled": true
9696
}

0 commit comments

Comments
 (0)