From 1d2ac44f6f83bbc13e4343b099b90b16babb0db4 Mon Sep 17 00:00:00 2001
From: Yoriiis <2563298+yoriiis@users.noreply.github.com>
Date: Wed, 18 Sep 2024 21:28:39 +0200
Subject: [PATCH 1/6] Add async on before render function
---
src/app.ts | 61 ++++++++++++++++++++++++++++++++----------------------
1 file changed, 36 insertions(+), 25 deletions(-)
diff --git a/src/app.ts b/src/app.ts
index b17094b..ef7c6d3 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -251,24 +251,30 @@ export default class App {
* Create the current component
*/
createComponent() {
- if (this.currentRoute) {
- if (this.currentRoute.isComponentClass && !this.currentRoute.isComponentClassReady) {
+ const currentRoute = this.currentRoute
+ if (currentRoute) {
+ if (currentRoute.isComponentClass && !currentRoute.isComponentClassReady) {
this.initComponentInCache()
}
- let componentView = this.getComponentView()
- if (componentView) {
- if (!this.currentRoute.interfaceType) {
- this.currentRoute.interfaceType = this.getInterfaceTypeFromView(componentView)
- this.routes.set(this.currentRoute.path, this.currentRoute)
- }
+ const responseComponentView = this.getComponentView()
- if (this.currentRoute.interfaceType === 'STRING') {
- componentView = this.transformLinksInStringComponent(componentView)
- }
- this.target.appendChild(componentView)
- this.currentRoute.isComponentClass && this.currentRoute.component.afterRender()
- }
+ responseComponentView &&
+ responseComponentView.then((componentView: any) => {
+ if (componentView) {
+ if (!currentRoute.interfaceType) {
+ currentRoute.interfaceType =
+ this.getInterfaceTypeFromView(componentView)
+ this.routes.set(currentRoute.path, currentRoute)
+ }
+
+ if (currentRoute.interfaceType === 'STRING') {
+ componentView = this.transformLinksInStringComponent(componentView)
+ }
+ this.target.appendChild(componentView)
+ currentRoute.isComponentClass && currentRoute.component.afterRender()
+ }
+ })
}
}
@@ -302,17 +308,22 @@ export default class App {
* @returns The component view
*/
getComponentView() {
- if (this.currentRoute) {
- if (this.currentRoute.isComponentClass) {
- this.updateComponentRouteData()
- this.currentRoute.component.beforeRender()
- return this.currentRoute.component.render()
- } else {
- return this.currentRoute.component.call(
- this.currentRoute.component,
- this.currentRoute.props
- )
- }
+ const currentRoute = this.currentRoute
+ if (currentRoute) {
+ return new Promise((resolve) => {
+ if (currentRoute.isComponentClass) {
+ this.updateComponentRouteData()
+ const beforeRenderFn = currentRoute.component.beforeRender()
+
+ if (beforeRenderFn instanceof Promise) {
+ beforeRenderFn.then(() => resolve(currentRoute.component.render()))
+ } else {
+ resolve(currentRoute.component.render())
+ }
+ } else {
+ resolve(currentRoute.component.call(currentRoute.component, currentRoute.props))
+ }
+ })
}
}
From 61223729bed2c4e0e83e4e0c067d4f7ef9d3c27d Mon Sep 17 00:00:00 2001
From: Yoriiis <2563298+yoriiis@users.noreply.github.com>
Date: Fri, 20 Sep 2024 16:51:08 +0200
Subject: [PATCH 2/6] Update
---
src/app.ts | 74 +++++++++++++++++++++++++++++++-----------------------
1 file changed, 43 insertions(+), 31 deletions(-)
diff --git a/src/app.ts b/src/app.ts
index ef7c6d3..3a20478 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -247,34 +247,40 @@ export default class App {
}
}
+ updateView() {
+ if (typeof Element.prototype.replaceChildren === 'function') {
+ this.target.replaceChildren()
+ } else {
+ this.target.innerHTML = ''
+ }
+ }
+
/**
* Create the current component
*/
createComponent() {
- const currentRoute = this.currentRoute
- if (currentRoute) {
- if (currentRoute.isComponentClass && !currentRoute.isComponentClassReady) {
+ if (this.currentRoute) {
+ if (this.currentRoute.isComponentClass && !this.currentRoute.isComponentClassReady) {
this.initComponentInCache()
}
const responseComponentView = this.getComponentView()
- responseComponentView &&
- responseComponentView.then((componentView: any) => {
- if (componentView) {
- if (!currentRoute.interfaceType) {
- currentRoute.interfaceType =
- this.getInterfaceTypeFromView(componentView)
- this.routes.set(currentRoute.path, currentRoute)
- }
+ responseComponentView.then((componentView: any) => {
+ if (componentView && this.currentRoute) {
+ if (!this.currentRoute.interfaceType) {
+ this.currentRoute.interfaceType =
+ this.getInterfaceTypeFromView(componentView)
+ this.routes.set(this.currentRoute.path, this.currentRoute)
+ }
- if (currentRoute.interfaceType === 'STRING') {
- componentView = this.transformLinksInStringComponent(componentView)
- }
- this.target.appendChild(componentView)
- currentRoute.isComponentClass && currentRoute.component.afterRender()
+ if (this.currentRoute.interfaceType === 'STRING') {
+ componentView = this.transformLinksInStringComponent(componentView)
}
- })
+ this.target.appendChild(componentView)
+ this.currentRoute.isComponentClass && this.currentRoute.component.afterRender()
+ }
+ })
}
}
@@ -308,23 +314,29 @@ export default class App {
* @returns The component view
*/
getComponentView() {
- const currentRoute = this.currentRoute
- if (currentRoute) {
- return new Promise((resolve) => {
- if (currentRoute.isComponentClass) {
- this.updateComponentRouteData()
- const beforeRenderFn = currentRoute.component.beforeRender()
-
- if (beforeRenderFn instanceof Promise) {
- beforeRenderFn.then(() => resolve(currentRoute.component.render()))
- } else {
- resolve(currentRoute.component.render())
- }
+ if (this.currentRoute) {
+ if (this.currentRoute.isComponentClass) {
+ this.updateComponentRouteData()
+ const beforeRenderFn = this.currentRoute.component.beforeRender()
+
+ if (beforeRenderFn instanceof Promise) {
+ return Promise.resolve(beforeRenderFn).then(
+ () => this.currentRoute && this.currentRoute.component.render()
+ )
} else {
- resolve(currentRoute.component.call(currentRoute.component, currentRoute.props))
+ return Promise.resolve(this.currentRoute.component.render())
}
- })
+ } else {
+ return Promise.resolve(
+ this.currentRoute.component.call(
+ this.currentRoute.component,
+ this.currentRoute.props
+ )
+ )
+ }
}
+
+ return Promise.reject()
}
/**
From a1abaabb5eb9b0c0f2eb87d9038a0f9724c01bac Mon Sep 17 00:00:00 2001
From: Yoriiis <2563298+yoriiis@users.noreply.github.com>
Date: Fri, 20 Sep 2024 17:36:31 +0200
Subject: [PATCH 3/6] Update unit test
---
src/app.ts | 8 ----
tests/unit/app.test.js | 97 ++++++++++++++++++++++++++----------------
2 files changed, 60 insertions(+), 45 deletions(-)
diff --git a/src/app.ts b/src/app.ts
index 3a20478..e9da64b 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -247,14 +247,6 @@ export default class App {
}
}
- updateView() {
- if (typeof Element.prototype.replaceChildren === 'function') {
- this.target.replaceChildren()
- } else {
- this.target.innerHTML = ''
- }
- }
-
/**
* Create the current component
*/
diff --git a/tests/unit/app.test.js b/tests/unit/app.test.js
index 6b86beb..3ac590d 100644
--- a/tests/unit/app.test.js
+++ b/tests/unit/app.test.js
@@ -687,7 +687,7 @@ describe('App', () => {
app = getInstance()
})
- it('should call the createComponent function with a component and HTMLElement', () => {
+ it('should call the createComponent function with a component and HTMLElement', async () => {
app.currentRoute = {
component: {
afterRender: jest.fn()
@@ -698,12 +698,12 @@ describe('App', () => {
}
app.initComponentInCache = jest.fn()
- app.getComponentView = jest.fn().mockReturnValue(
Component
)
+ app.getComponentView = jest.fn().mockResolvedValue(Component
)
app.getInterfaceTypeFromView = jest.fn().mockReturnValue('ELEMENT_NODE')
app.transformLinksInStringComponent = jest.fn()
app.target.appendChild = jest.fn()
- app.createComponent()
+ await app.createComponent()
expect(app.initComponentInCache).toHaveBeenCalled()
expect(app.getComponentView).toHaveBeenCalled()
@@ -714,7 +714,7 @@ describe('App', () => {
expect(app.currentRoute.component.afterRender).toHaveBeenCalled()
})
- it('should call the createComponent function with a component and String', () => {
+ it('should call the createComponent function with a component and String', async () => {
app.currentRoute = {
component: {
afterRender: jest.fn()
@@ -727,12 +727,12 @@ describe('App', () => {
app.initComponentInCache = jest.fn()
app.getComponentView = jest
.fn()
- .mockReturnValue('')
+ .mockResolvedValue('')
app.getInterfaceTypeFromView = jest.fn().mockReturnValue('STRING')
app.transformLinksInStringComponent = jest.fn().mockReturnValue()
app.target.appendChild = jest.fn()
- app.createComponent()
+ await app.createComponent()
expect(app.initComponentInCache).toHaveBeenCalled()
expect(app.getComponentView).toHaveBeenCalled()
@@ -808,44 +808,67 @@ describe('App', () => {
app.updateComponentRouteData = jest.fn()
})
- it('should call the getComponentView function with a component class', () => {
- app.currentRoute = {
- component: {
- afterRender: jest.fn(),
- beforeRender: jest.fn(),
- render: jest.fn().mockReturnValue(Component
)
- },
- isComponentClass: true
- }
+ describe('Component', () => {
+ it('should call the getComponentView function with a component class with before render not asynchrone', async () => {
+ app.currentRoute = {
+ component: {
+ afterRender: jest.fn(),
+ beforeRender: jest.fn(),
+ render: jest.fn().mockReturnValue(Component
)
+ },
+ isComponentClass: true
+ }
- const result = app.getComponentView()
+ const result = await app.getComponentView()
- expect(app.updateComponentRouteData).toHaveBeenCalled()
- expect(app.currentRoute.component.beforeRender).toHaveBeenCalled()
- expect(app.currentRoute.component.render).toHaveBeenCalled()
- expect(result).toStrictEqual(Component
)
- })
+ expect(app.updateComponentRouteData).toHaveBeenCalled()
+ expect(app.currentRoute.component.beforeRender).toHaveBeenCalled()
+ expect(app.currentRoute.component.render).toHaveBeenCalled()
+ expect(result).toStrictEqual(Component
)
+ })
- it('should call the getComponentView function with not a component class', () => {
- app.currentRoute = {
- component: jest.fn().mockReturnValue(Component
),
- isComponentClass: false,
- props: {
- name: 'John Doe'
+ it('should call the getComponentView function with a component class with before render asynchrone', async () => {
+ app.currentRoute = {
+ component: {
+ afterRender: jest.fn(),
+ beforeRender: jest.fn().mockResolvedValue(),
+ render: jest.fn().mockReturnValue(Component
)
+ },
+ isComponentClass: true
}
- }
- jest.spyOn(app.currentRoute.component, 'call')
- const result = app.getComponentView()
+ const result = await app.getComponentView()
+
+ expect(app.updateComponentRouteData).toHaveBeenCalled()
+ expect(app.currentRoute.component.beforeRender).toHaveBeenCalled()
+ // TODO check execution order
+ expect(app.currentRoute.component.render).toHaveBeenCalled()
+ expect(result).toStrictEqual(Component
)
+ })
+ })
- expect(app.updateComponentRouteData).not.toHaveBeenCalled()
- expect(app.currentRoute.component.call).toHaveBeenCalledWith(
- app.currentRoute.component,
- {
- name: 'John Doe'
+ describe('Not a component', () => {
+ it('should call the getComponentView function with not a component class', async () => {
+ app.currentRoute = {
+ component: jest.fn().mockReturnValue(Component
),
+ isComponentClass: false,
+ props: {
+ name: 'John Doe'
+ }
}
- )
- expect(result).toStrictEqual(Component
)
+ jest.spyOn(app.currentRoute.component, 'call')
+
+ const result = await app.getComponentView()
+
+ expect(app.updateComponentRouteData).not.toHaveBeenCalled()
+ expect(app.currentRoute.component.call).toHaveBeenCalledWith(
+ app.currentRoute.component,
+ {
+ name: 'John Doe'
+ }
+ )
+ expect(result).toStrictEqual(Component
)
+ })
})
})
From 2f653d1f9ab00915a8158971a7131ef52b43cac7 Mon Sep 17 00:00:00 2001
From: Yoriiis <2563298+yoriiis@users.noreply.github.com>
Date: Mon, 23 Sep 2024 17:39:46 +0200
Subject: [PATCH 4/6] Update unit test
---
src/app.ts | 72 +++++++++++++---------
tests/unit/app.test.js | 135 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 173 insertions(+), 34 deletions(-)
diff --git a/src/app.ts b/src/app.ts
index e9da64b..8ccd1ce 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -256,23 +256,26 @@ export default class App {
this.initComponentInCache()
}
- const responseComponentView = this.getComponentView()
-
- responseComponentView.then((componentView: any) => {
- if (componentView && this.currentRoute) {
- if (!this.currentRoute.interfaceType) {
- this.currentRoute.interfaceType =
- this.getInterfaceTypeFromView(componentView)
- this.routes.set(this.currentRoute.path, this.currentRoute)
- }
+ try {
+ this.getComponentView().then((componentView) => {
+ if (componentView && this.currentRoute) {
+ if (!this.currentRoute.interfaceType) {
+ this.currentRoute.interfaceType =
+ this.getInterfaceTypeFromView(componentView)
+ this.routes.set(this.currentRoute.path, this.currentRoute)
+ }
- if (this.currentRoute.interfaceType === 'STRING') {
- componentView = this.transformLinksInStringComponent(componentView)
+ if (this.currentRoute.interfaceType === 'STRING') {
+ componentView = this.transformLinksInStringComponent(componentView)
+ }
+ this.target.appendChild(componentView)
+ this.currentRoute.isComponentClass &&
+ this.currentRoute.component.afterRender()
}
- this.target.appendChild(componentView)
- this.currentRoute.isComponentClass && this.currentRoute.component.afterRender()
- }
- })
+ })
+ } catch (error) {
+ console.warn('getComponentView::promise rejected')
+ }
}
}
@@ -312,23 +315,36 @@ export default class App {
const beforeRenderFn = this.currentRoute.component.beforeRender()
if (beforeRenderFn instanceof Promise) {
- return Promise.resolve(beforeRenderFn).then(
- () => this.currentRoute && this.currentRoute.component.render()
- )
- } else {
- return Promise.resolve(this.currentRoute.component.render())
+ return this.runRenderWhenReady(this.currentRoute, beforeRenderFn)
}
- } else {
- return Promise.resolve(
- this.currentRoute.component.call(
- this.currentRoute.component,
- this.currentRoute.props
- )
- )
+
+ return Promise.resolve(this.currentRoute.component.render())
}
+
+ return Promise.resolve(
+ this.currentRoute.component.call(
+ this.currentRoute.component,
+ this.currentRoute.props
+ )
+ )
}
- return Promise.reject()
+ return Promise.reject(new Error('getComponentView::promise not resolved'))
+ }
+
+ /**
+ * Run render function when asynchronous before render is resolved
+ * @param currentRoute Current route
+ * @param beforeRenderFn Before render promise
+ * @returns The render content
+ */
+ runRenderWhenReady(currentRoute: RouteData, beforeRenderFn: Promise) {
+ return Promise.resolve(beforeRenderFn).then(() => {
+ // Check is route has changed before the promise resolution
+ if (this.currentRoute && this.currentRoute.path === currentRoute.path) {
+ return currentRoute.component.render()
+ }
+ })
}
/**
diff --git a/tests/unit/app.test.js b/tests/unit/app.test.js
index 3ac590d..e9e74ec 100644
--- a/tests/unit/app.test.js
+++ b/tests/unit/app.test.js
@@ -744,6 +744,34 @@ describe('App', () => {
expect(app.target.appendChild).toHaveBeenCalledWith()
expect(app.currentRoute.component.afterRender).toHaveBeenCalled()
})
+
+ it('should call the createComponent function with a promise rejected', async () => {
+ app.currentRoute = {
+ component: {
+ afterRender: jest.fn()
+ },
+ interfaceType: null,
+ isComponentClass: true,
+ isComponentClassReady: false
+ }
+
+ app.initComponentInCache = jest.fn()
+ app.getComponentView = jest.fn()
+ app.getInterfaceTypeFromView = jest.fn()
+ app.transformLinksInStringComponent = jest.fn()
+ app.target.appendChild = jest.fn()
+ console.warn = jest.fn()
+
+ await app.createComponent()
+
+ expect(app.initComponentInCache).toHaveBeenCalled()
+ expect(app.getComponentView).toHaveBeenCalled()
+ expect(app.getInterfaceTypeFromView).not.toHaveBeenCalled()
+ expect(app.transformLinksInStringComponent).not.toHaveBeenCalled()
+ expect(app.target.appendChild).not.toHaveBeenCalled()
+ expect(app.currentRoute.component.afterRender).not.toHaveBeenCalled()
+ expect(console.warn).toHaveBeenCalledWith('getComponentView::promise rejected')
+ })
})
describe('initComponentInCache', () => {
@@ -809,7 +837,7 @@ describe('App', () => {
})
describe('Component', () => {
- it('should call the getComponentView function with a component class with before render not asynchrone', async () => {
+ it('should call the getComponentView function with a component class with before render not a promise', async () => {
app.currentRoute = {
component: {
afterRender: jest.fn(),
@@ -818,31 +846,63 @@ describe('App', () => {
},
isComponentClass: true
}
+ app.runRenderWhenReady = jest.fn()
const result = await app.getComponentView()
expect(app.updateComponentRouteData).toHaveBeenCalled()
expect(app.currentRoute.component.beforeRender).toHaveBeenCalled()
+ expect(app.runRenderWhenReady).not.toHaveBeenCalled()
expect(app.currentRoute.component.render).toHaveBeenCalled()
expect(result).toStrictEqual(Component
)
})
- it('should call the getComponentView function with a component class with before render asynchrone', async () => {
+ it('should call the getComponentView function with a component class with before render as a promise', async () => {
app.currentRoute = {
component: {
afterRender: jest.fn(),
- beforeRender: jest.fn().mockResolvedValue(),
- render: jest.fn().mockReturnValue(Component
)
+ beforeRender: jest
+ .fn()
+ .mockImplementation(
+ () => new Promise((resolve) => setTimeout(resolve, 2000))
+ ),
+ render: jest.fn()
},
isComponentClass: true
}
+ app.runRenderWhenReady = jest.fn().mockResolvedValue(Component
)
const result = await app.getComponentView()
expect(app.updateComponentRouteData).toHaveBeenCalled()
expect(app.currentRoute.component.beforeRender).toHaveBeenCalled()
- // TODO check execution order
- expect(app.currentRoute.component.render).toHaveBeenCalled()
+ expect(app.runRenderWhenReady).toHaveBeenCalled()
+ expect(app.currentRoute.component.render).not.toHaveBeenCalled()
+ expect(result).toStrictEqual(Component
)
+ })
+
+ it('should call the getComponentView function with a component class with before render as a promise and route has changed', async () => {
+ const beforeRenderMock = jest.fn().mockResolvedValue()
+
+ app.currentRoute = {
+ component: {
+ afterRender: jest.fn(),
+ beforeRender: beforeRenderMock,
+ render: jest.fn()
+ },
+ isComponentClass: true
+ }
+ app.runRenderWhenReady = jest.fn().mockResolvedValue(Component
)
+
+ const result = await app.getComponentView()
+
+ expect(app.updateComponentRouteData).toHaveBeenCalled()
+ expect(app.currentRoute.component.beforeRender).toHaveBeenCalled()
+ expect(app.runRenderWhenReady).toHaveBeenCalledWith(
+ app.currentRoute,
+ expect.any(Promise)
+ )
+ expect(app.currentRoute.component.render).not.toHaveBeenCalled()
expect(result).toStrictEqual(Component
)
})
})
@@ -870,6 +930,69 @@ describe('App', () => {
expect(result).toStrictEqual(Component
)
})
})
+
+ it('should call the getComponentView function with a promise rejection', async () => {
+ await expect(app.getComponentView()).rejects.toStrictEqual(
+ new Error('getComponentView::promise not resolved')
+ )
+ })
+ })
+
+ describe('runRenderWhenReady', () => {
+ beforeEach(() => {
+ jest.spyOn(App.prototype, 'createRoutesData').mockReturnValue(customRoutes)
+ jest.spyOn(App.prototype, 'addEvents').mockImplementation(() => {
+ /* Empty */
+ })
+ jest.spyOn(App.prototype, 'onRouteChange').mockImplementation(() => {
+ /* Empty */
+ })
+
+ app = getInstance()
+ app.updateComponentRouteData = jest.fn()
+ })
+
+ it('should call the runRenderWhenReady function with render function called', async () => {
+ app.currentRoute = {
+ component: {
+ render: jest.fn().mockReturnValue(Component
)
+ },
+ isComponentClass: true,
+ path: '/home'
+ }
+
+ const result = await app.runRenderWhenReady(
+ app.currentRoute,
+ jest.fn().mockResolvedValue()
+ )
+
+ expect(app.currentRoute.component.render).toHaveBeenCalled()
+ expect(result).toStrictEqual(Component
)
+ })
+
+ it('should call the runRenderWhenReady function with route changed and render function not called', async () => {
+ app.currentRoute = {
+ component: {
+ render: jest.fn().mockReturnValue(Component
)
+ },
+ path: '/page-2'
+ }
+
+ const previousRoute = {
+ component: {
+ render: jest.fn().mockReturnValue(Component
)
+ },
+ path: '/page-1'
+ }
+
+ const result = await app.runRenderWhenReady(
+ previousRoute,
+ jest.fn().mockResolvedValue()
+ )
+
+ expect(app.currentRoute.component.render).not.toHaveBeenCalled()
+ expect(result).toStrictEqual(undefined)
+ })
})
describe('updateComponentRouteData', () => {
From 02b578f2060ec41b07131c5765438f32ec4a18f3 Mon Sep 17 00:00:00 2001
From: Yoriiis <2563298+yoriiis@users.noreply.github.com>
Date: Mon, 23 Sep 2024 18:06:18 +0200
Subject: [PATCH 5/6] Update version
---
CHANGELOG.md | 6 ++++++
package-lock.json | 4 ++--
package.json | 2 +-
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 824db62..e818a0b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# CHANGELOG
+## 2.2.0
+
+### New features
+
+- Add asynchronous `beforeRender` hook ([#20](https://github.com/costrojs/costro/pull/20))
+
## 2.1.2
### Fixes
diff --git a/package-lock.json b/package-lock.json
index 2be5363..14927f7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "costro",
- "version": "2.1.2",
+ "version": "2.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "costro",
- "version": "2.1.2",
+ "version": "2.2.0",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.21.8",
diff --git a/package.json b/package.json
index 2b18703..85627cd 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "costro",
- "version": "2.1.2",
+ "version": "2.2.0",
"description": "Build web applications with Components, Store and Router in 3KB",
"keywords": [
"costro",
From 0f7938db62ee4da2bc4395af319ce2537a888c8b Mon Sep 17 00:00:00 2001
From: Yoriiis <2563298+yoriiis@users.noreply.github.com>
Date: Tue, 24 Sep 2024 14:41:17 +0200
Subject: [PATCH 6/6] Optimize catch
---
src/app.ts | 10 +++++-----
tests/unit/app.test.js | 42 +++++++++++++++++++++++++++++++++---------
2 files changed, 38 insertions(+), 14 deletions(-)
diff --git a/src/app.ts b/src/app.ts
index 8ccd1ce..53ba082 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -256,8 +256,8 @@ export default class App {
this.initComponentInCache()
}
- try {
- this.getComponentView().then((componentView) => {
+ this.getComponentView()
+ .then((componentView) => {
if (componentView && this.currentRoute) {
if (!this.currentRoute.interfaceType) {
this.currentRoute.interfaceType =
@@ -273,9 +273,9 @@ export default class App {
this.currentRoute.component.afterRender()
}
})
- } catch (error) {
- console.warn('getComponentView::promise rejected')
- }
+ .catch((error) => {
+ console.warn('getComponentView::promise rejected', error)
+ })
}
}
diff --git a/tests/unit/app.test.js b/tests/unit/app.test.js
index e9e74ec..2056691 100644
--- a/tests/unit/app.test.js
+++ b/tests/unit/app.test.js
@@ -745,6 +745,33 @@ describe('App', () => {
expect(app.currentRoute.component.afterRender).toHaveBeenCalled()
})
+ it('should call the createComponent function with a promise returning undefined (route has changed)', async () => {
+ app.currentRoute = {
+ component: {
+ afterRender: jest.fn()
+ },
+ interfaceType: null,
+ isComponentClass: true,
+ isComponentClassReady: false
+ }
+
+ app.initComponentInCache = jest.fn()
+ app.getComponentView = jest.fn().mockResolvedValue(undefined)
+ app.getInterfaceTypeFromView = jest.fn()
+ app.transformLinksInStringComponent = jest.fn()
+ app.target.appendChild = jest.fn()
+ console.warn = jest.fn()
+
+ await app.createComponent()
+
+ expect(app.initComponentInCache).toHaveBeenCalled()
+ expect(app.getComponentView).toHaveBeenCalled()
+ expect(app.getInterfaceTypeFromView).not.toHaveBeenCalled()
+ expect(app.transformLinksInStringComponent).not.toHaveBeenCalled()
+ expect(app.target.appendChild).not.toHaveBeenCalled()
+ expect(app.currentRoute.component.afterRender).not.toHaveBeenCalled()
+ })
+
it('should call the createComponent function with a promise rejected', async () => {
app.currentRoute = {
component: {
@@ -756,10 +783,12 @@ describe('App', () => {
}
app.initComponentInCache = jest.fn()
- app.getComponentView = jest.fn()
+ app.getComponentView = jest.fn().mockRejectedValue(new Error('Promise rejection error'))
+
app.getInterfaceTypeFromView = jest.fn()
app.transformLinksInStringComponent = jest.fn()
app.target.appendChild = jest.fn()
+ app.test = jest.fn()
console.warn = jest.fn()
await app.createComponent()
@@ -770,7 +799,6 @@ describe('App', () => {
expect(app.transformLinksInStringComponent).not.toHaveBeenCalled()
expect(app.target.appendChild).not.toHaveBeenCalled()
expect(app.currentRoute.component.afterRender).not.toHaveBeenCalled()
- expect(console.warn).toHaveBeenCalledWith('getComponentView::promise rejected')
})
})
@@ -857,15 +885,11 @@ describe('App', () => {
expect(result).toStrictEqual(Component
)
})
- it('should call the getComponentView function with a component class with before render as a promise', async () => {
+ it('should call the getComponentView function with a component class with before render a promise', async () => {
app.currentRoute = {
component: {
afterRender: jest.fn(),
- beforeRender: jest
- .fn()
- .mockImplementation(
- () => new Promise((resolve) => setTimeout(resolve, 2000))
- ),
+ beforeRender: jest.fn().mockResolvedValue(),
render: jest.fn()
},
isComponentClass: true
@@ -881,7 +905,7 @@ describe('App', () => {
expect(result).toStrictEqual(Component
)
})
- it('should call the getComponentView function with a component class with before render as a promise and route has changed', async () => {
+ it('should call the getComponentView function with a component class with before render a promise and route has changed', async () => {
const beforeRenderMock = jest.fn().mockResolvedValue()
app.currentRoute = {