Skip to content

Commit

Permalink
chore: add more template files to app actions and remove deploy scrip…
Browse files Browse the repository at this point in the history
…ts from frontend
  • Loading branch information
whitelisab committed Aug 16, 2024
1 parent 182c605 commit 59cc866
Show file tree
Hide file tree
Showing 18 changed files with 270 additions and 14 deletions.
7 changes: 7 additions & 0 deletions apps/sap-commerce-cloud/app-actions/.mocharc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
recursive: true
reporter: 'spec'
require:
- 'ts-node/register'
- './test/hooks.ts'
spec:
- 'src/**/*.spec.ts' # the positional arguments!
1 change: 1 addition & 0 deletions apps/sap-commerce-cloud/app-actions/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lts/hydrogen
1 change: 1 addition & 0 deletions apps/sap-commerce-cloud/app-actions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# SAP App Actions
32 changes: 32 additions & 0 deletions apps/sap-commerce-cloud/app-actions/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions apps/sap-commerce-cloud/app-actions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@
},
"dependencies": {
"@contentful/node-apps-toolkit": "^2.6.0",
"lodash.difference": "^4.5.0",
"lodash.get": "^4.4.2"
},
"devDependencies": {
"@tsconfig/node18": "^18.2.0",
"@types/chai": "^4.3.5",
"@types/lodash.difference": "^4.5.9",
"@types/lodash.get": "^4.4.9",
"@types/mocha": "^10.0.1",
"@types/sinon": "^10.0.16",
"@types/sinon-chai": "^3.2.12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ export const handler = async (payload: AppActionCallParameters, context: AppActi

return {
status: 'Success',
// @ts-ignore
baseSites: res.baseSites,
};
} catch (err) {
return {
status: 'Failed',
// @ts-ignore
body: err.message,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const handler = async (payload: AppActionCallParameters, context: AppActi
} catch (err) {
return {
success: false,
// @ts-ignore
body: err.message,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ export const handler = async (payload: AppActionCallParameters) => {
},
});
const json = await req.json();
// @ts-ignore
totalProducts.push(json);
// @ts-ignore
skuIds.push(`${json.code}`);
})
);
Expand All @@ -74,6 +76,7 @@ export const handler = async (payload: AppActionCallParameters) => {
} catch (err) {
return {
status: 'Failed',
// @ts-ignore
body: err.message,
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect } from 'chai';
import sinon from 'sinon';
import { makeMockAppActionCallContext } from '../../test/mocks';
import { AppInstallationProps, SysLink } from 'contentful-management';
import { AppActionCallContext } from '@contentful/node-apps-toolkit';
import { handler } from './testHandler';

describe('testHandler.handler', () => {
let cmaRequestStub: sinon.SinonStub;
let context: AppActionCallContext;

const cmaClientMockResponses: [AppInstallationProps] = [
{
sys: {
type: 'AppInstallation',
appDefinition: {} as SysLink,
environment: {} as SysLink,
space: {} as SysLink,
version: 1,
createdAt: 'createdAt',
updatedAt: 'updatedAt',
},
parameters: {
sapApiEndpoint: 'sap-endpoint',
apiKey: 'sap-api-key',
},
},
];

beforeEach(() => {
cmaRequestStub = sinon.stub();
context = makeMockAppActionCallContext(cmaClientMockResponses, cmaRequestStub);
});

it('returns the base sites result', async () => {
const result = await handler(
{ sapApiEndpoint: 'sap-endpoint', apiKey: 'sap-api-key' },
context
);

expect(result).to.have.property('ok', true);
});
});
17 changes: 17 additions & 0 deletions apps/sap-commerce-cloud/app-actions/src/actions/testHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AppActionCallContext } from '@contentful/node-apps-toolkit';
import { AppActionCallResponse, BaseSites } from '../types';
import { withAsyncAppActionErrorHandling } from '../helpers/error-handling';

interface AppActionCallParameters {}

export const handler = withAsyncAppActionErrorHandling(
async (
_payload: AppActionCallParameters,
_context: AppActionCallContext
): Promise<AppActionCallResponse<BaseSites>> => {
return {
ok: true,
data: [{ channel: 'B2B', name: 'Fashion Site', uid: 'fashion-spa' }],
};
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { expect } from 'chai';
import { withAsyncAppActionErrorHandling } from './error-handling';
import { AppActionCallResponse } from '../types';

describe('withAsyncAppActionErrorHandling', () => {
const testHandler = async (arg: string): Promise<AppActionCallResponse<string>> => {
return { ok: true, data: arg };
};

it('returns a function that continues to work as normal with no errors', async () => {
const newFunc = withAsyncAppActionErrorHandling(testHandler);
const result = await newFunc('hello');
expect(result).to.deep.equal({ ok: true, data: 'hello' });
});

describe('when handler throws an error', () => {
const testHandler = async (_arg: string): Promise<AppActionCallResponse<string>> => {
throw new TypeError('boom!');
};

it('returns a function that returns an error result without throwing', async () => {
const newFunc = withAsyncAppActionErrorHandling(testHandler);
const result = await newFunc('hello');
expect(result).to.deep.equal({ ok: false, error: { message: 'boom!', type: 'TypeError' } });
});
});
});
42 changes: 42 additions & 0 deletions apps/sap-commerce-cloud/app-actions/src/helpers/error-handling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { AppActionCallResponse, AppActionCallResponseError } from '../types';

// for the purposes of the error handler, a HandlerFunction is one that can take any arguments and return any value -- provided
// it _can_ return an AppActionCallResponseError
type HandlerFunction<TFnReturn, TFnArgs extends unknown[]> = (
...args: TFnArgs
) => Promise<TFnReturn | AppActionCallResponseError>;

// function wrapper intended of handlers (but really any function that returns our AppActionCallResponse type)
export const withAsyncAppActionErrorHandling = <
TResponseType,
TFnReturn extends AppActionCallResponse<TResponseType>,
TFnArgs extends unknown[]
>(
fn: HandlerFunction<TFnReturn, TFnArgs>
): HandlerFunction<TFnReturn, TFnArgs> => {
const wrappedHandler: HandlerFunction<TFnReturn, TFnArgs> = async (...args) => {
try {
return await fn(...args);
} catch (e) {
// this is mostly for typescript, to handle the case where a non-Error object gets thrown
if (!(e instanceof Error)) {
return {
ok: false,
error: {
message: JSON.stringify(e),
type: 'UnknownError',
},
};
}

return {
ok: false,
error: {
type: e.constructor.name,
message: e.message,
},
};
}
};
return wrappedHandler;
};
27 changes: 27 additions & 0 deletions apps/sap-commerce-cloud/app-actions/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,30 @@ export interface ConfigurationParameters {
fieldsConfig?: FieldsConfig;
baseSites?: string;
}

export interface ActionError {
type: string;
message: string;
details?: Record<string, any>;
}

export interface AppActionCallResponseSuccess<TResult> {
ok: true;
data: TResult;
}

export interface AppActionCallResponseError {
ok: false;
error: ActionError;
}

export type AppActionCallResponse<T> = AppActionCallResponseSuccess<T> | AppActionCallResponseError;

// WIP types
export interface BaseSite {
channel: string;
name: string;
uid: string;
}

export type BaseSites = BaseSite[];
7 changes: 7 additions & 0 deletions apps/sap-commerce-cloud/app-actions/test/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import sinon from 'sinon';

export const mochaHooks = {
afterEach() {
sinon.restore();
},
};
40 changes: 40 additions & 0 deletions apps/sap-commerce-cloud/app-actions/test/mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { AppActionCallContext } from '@contentful/node-apps-toolkit';
import { Adapter, PlainClientAPI, createClient } from 'contentful-management';
import sinon from 'sinon';

export const makeMockPlainClient = (responses: any[], stub: sinon.SinonStub): PlainClientAPI => {
for (const [callNumber, response] of responses.entries()) {
stub.onCall(callNumber).returns(response);
}
const apiAdapter: Adapter = {
makeRequest: async <T>(args: T) => {
return stub(args);
},
};
return createClient({ apiAdapter }, { type: 'plain' });
};

export const makeMockFetchResponse = (
body: object,
headers: Record<string, string> = {}
): Response => {
const responseBody = JSON.stringify(body);
return new Response(responseBody, { headers });
};

export const makeMockAppActionCallContext = (
responses: any[],
cmaStub = sinon.stub()
): AppActionCallContext => {
return {
cma: makeMockPlainClient(responses, cmaStub),
appActionCallContext: {
spaceId: 'space-id',
environmentId: 'environment-id',
appInstallationId: 'app-installation-id',
userId: 'user-id',
cmaHost: 'api.contentful.com',
uploadHost: 'upload.contentful.com',
},
};
};
10 changes: 10 additions & 0 deletions apps/sap-commerce-cloud/app-actions/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"compilerOptions": {
"outDir": "./build",
"sourceMap": false,
"target": "es2022"
},
"include": ["src"],
"exclude": ["node_modules"]
}
8 changes: 4 additions & 4 deletions apps/sap-commerce-cloud/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 3 additions & 10 deletions apps/sap-commerce-cloud/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sap-commerce",
"version": "0.2.0",
"name": "@contenful/sap-commerce-cloud-frontend",
"version": "1.0.0",
"private": true,
"homepage": "./",
"dependencies": {
Expand All @@ -23,14 +23,7 @@
"start": "vite",
"build": "vite build",
"test": "vitest --logHeapUsage --coverage",
"test:ci": "vitest",
"deploy": "npm run deploy:sap && npm run deploy:sap-with-air",
"deploy:sap": "contentful-app-scripts upload --ci --bundle-dir ./build --organization-id ${DEFINITIONS_ORG_ID} --definition-id GdOFzqcDrEbmn2teDQE2i --token ${CONTENTFUL_CMA_TOKEN}",
"deploy:sap-with-air": "contentful-app-scripts upload --ci --bundle-dir ./build --organization-id ${DEFINITIONS_ORG_ID} --definition-id 1PoDbrB3qO6oaN6uANGhK2 --token ${CONTENTFUL_CMA_TOKEN}",
"deploy:test": "npm run deploy:test:sap && npm run deploy:test:sap-with-air",
"deploy:test:sap": "contentful-app-scripts upload --ci --bundle-dir ./build --organization-id ${DEV_TESTING_ORG_ID} --definition-id 7xd4hIywW2diyQTdedfE8U --token ${TEST_CMA_TOKEN}",
"deploy:test:sap-with-air": "contentful-app-scripts upload --ci --bundle-dir ./build --organization-id ${DEV_TESTING_ORG_ID} --definition-id 6iZK9k1JbcwNdyK7Dg3aEm --token ${TEST_CMA_TOKEN}",
"eject": "react-scripts eject"
"test:ci": "vitest"
},
"eslintConfig": {
"extends": "react-app"
Expand Down

0 comments on commit 59cc866

Please sign in to comment.