Skip to content

Commit 34e4ae1

Browse files
committed
SVY-20819 use signals instead of @input in our components
update cy tests
1 parent d6cb0d3 commit 34e4ae1

28 files changed

Lines changed: 2499 additions & 1962 deletions

File tree

components/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"zone.js": "0.16.0"
3030
},
3131
"devDependencies": {
32+
"@angular-devkit/build-angular": "21.1.1",
3233
"@angular-devkit/core": "21.1.1",
3334
"@angular-devkit/schematics": "21.1.1",
3435
"@angular-eslint/builder": "21.1.0",
@@ -51,7 +52,7 @@
5152
"@typescript-eslint/utils": "^8.53.1",
5253
"adm-zip": "0.5.16",
5354
"css-loader": "^7.1.2",
54-
"cypress": "14.5.2",
55+
"cypress": "15.9.0",
5556
"eslint": "^9.39.2",
5657
"eslint-plugin-only-warn": "1.1.0",
5758
"eslint-plugin-prefer-arrow": "1.2.3",
@@ -60,4 +61,4 @@
6061
"style-loader": "^4.0.0",
6162
"typescript": "5.9.3"
6263
}
63-
}
64+
}

components/projects/bootstrapcomponents/src/accordion/accordion.cy.ts

Lines changed: 147 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -2,159 +2,181 @@
22
import { ServoyBootstrapAccordion } from './accordion'
33
import { MountConfig } from 'cypress/angular'
44
import { ServoyApi, ServoyApiTesting, ServoyPublicTestingModule } from '@servoy/public'
5-
import { Component, SimpleChange, SimpleChanges, ViewChild } from '@angular/core';
5+
import { Component, ViewChild, signal } from '@angular/core';
66
import { Tab } from '../bts_basetabpanel';
77
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
88

99
@Component({
10-
template: `
10+
template: `
1111
<bootstrapcomponents-accordion
1212
[servoyApi]="servoyApi"
13-
[enabled]="enabled"
14-
[height]="height"
13+
[enabled]="enabled()"
14+
[height]="height()"
1515
[onChangeMethodID]="onChangeMethodID"
16-
[styleClass]="styleClass"
17-
[tabIndex]="tabIndex"
18-
[tabs]="tabs"
16+
[styleClass]="styleClass()"
17+
[tabIndex]="tabIndex()"
18+
[tabs]="tabs()"
1919
#element>
2020
</bootstrapcomponents-accordion>
2121
`,
22-
standalone: false
22+
standalone: false
2323
})
2424
class WrapperComponent {
25-
enabled: boolean;
26-
height: number;
27-
28-
onChangeMethodID: (data?: any, e?: Event) => void;
29-
servoyApi: ServoyApi;
25+
enabled = signal<boolean>(undefined);
26+
height = signal<number>(undefined);
27+
onChangeMethodID: (data?: any, e?: Event) => void;
28+
servoyApi: ServoyApi;
29+
tabIndex = signal<number>(undefined);
30+
tabs = signal<Tab[]>(undefined);
31+
styleClass = signal<string>(undefined);
32+
33+
@ViewChild('element') element: ServoyBootstrapAccordion;
34+
}
3035

31-
tabIndex: number;
32-
tabs: Tab[];
33-
styleClass: string;
36+
const defaultValues = {
37+
servoyApi: new ServoyApiTesting(),
38+
enabled: true,
39+
height: 100,
40+
onChangeMethodID: undefined,
41+
styleClass: undefined,
42+
tabIndex: undefined,
43+
tabs: [] as Tab[]
44+
};
45+
46+
function createDefaultTabs(): Tab[] {
47+
const tabs = [];
48+
let tab = new Tab();
49+
tab.name = 'tab1';
50+
tab.containedForm = 'form1';
51+
tab.text = 'tab1';
52+
tab.disabled = false;
53+
tabs[0] = tab;
54+
tab = new Tab();
55+
tab.name = 'tab2';
56+
tab.containedForm = 'form2';
57+
tab.text = 'tab2';
58+
tab.disabled = false;
59+
tabs[1] = tab;
60+
tab = new Tab();
61+
tab.name = 'tab3';
62+
tab.containedForm = 'form3';
63+
tab.text = 'tab3';
64+
tab.disabled = false;
65+
tabs[2] = tab;
66+
return tabs;
67+
}
3468

35-
@ViewChild('element') element: ServoyBootstrapAccordion;
69+
function applyDefaultProps(wrapper) {
70+
for (const key in defaultValues) {
71+
if (wrapper.component.hasOwnProperty(key) && typeof wrapper.component[key] === 'function') {
72+
// If the property is a signal, update it using .set()
73+
if (key === 'tabs' && (!defaultValues[key] || defaultValues[key].length === 0)) {
74+
wrapper.component[key].set(createDefaultTabs());
75+
} else {
76+
wrapper.component[key].set(defaultValues[key]);
77+
}
78+
}
79+
else {
80+
// Otherwise assign it as a normal property
81+
wrapper.component[key] = defaultValues[key];
82+
}
83+
}
3684
}
3785

3886
describe('ServoyBootstrapAccordion', () => {
39-
const servoyApiSpy = new ServoyApiTesting();
40-
41-
const config: MountConfig<ServoyBootstrapAccordion> = {
42-
declarations: [ServoyBootstrapAccordion],
43-
imports: [ServoyPublicTestingModule, NgbModule],
44-
}
45-
46-
beforeEach(() => {
47-
const tabs = [];
48-
let tab = new Tab();
49-
tab.name = 'tab1';
50-
tab.containedForm = 'form1';
51-
tab.text = 'tab1';
52-
tab.disabled = false;
53-
tabs[0] = tab;
54-
tab = new Tab();
55-
tab.name = 'tab2';
56-
tab.containedForm = 'form2';
57-
tab.text = 'tab2';
58-
tab.disabled = false;
59-
tabs[1] = tab;
60-
tab = new Tab();
61-
tab.name = 'tab3';
62-
tab.containedForm = 'form3';
63-
tab.text = 'tab3';
64-
tab.disabled = false;
65-
tabs[2] = tab;
66-
config.componentProperties = {
67-
servoyApi: servoyApiSpy,
68-
enabled: true,
69-
tabs: tabs,
70-
height: 100,
71-
}
72-
});
73-
74-
it('should mount and register the component', () => {
75-
const registerComponent = cy.stub(servoyApiSpy, 'registerComponent');
76-
cy.mount(WrapperComponent, config).then(() => {
77-
cy.get('.bts-accordion').should('exist').then(() => {
78-
cy.wrap(registerComponent).should('be.called');
79-
});
80-
});
81-
});
82-
83-
84-
it('should handle tabs', () => {
85-
const onChangeMethodID = cy.stub();
86-
config.componentProperties.onChangeMethodID = onChangeMethodID;
87+
const configWrapper: MountConfig<WrapperComponent> = {
88+
declarations: [ServoyBootstrapAccordion],
89+
imports: [ServoyPublicTestingModule, NgbModule],
90+
};
91+
92+
beforeEach(() => {
93+
defaultValues.tabs = createDefaultTabs();
94+
});
95+
96+
it('should mount and register the component', () => {
97+
const servoyApiSpy = defaultValues.servoyApi;
98+
const registerComponent = cy.stub(servoyApiSpy, 'registerComponent');
99+
cy.mount(WrapperComponent, configWrapper).then((wrapper) => {
100+
applyDefaultProps(wrapper);
101+
cy.get('.bts-accordion').should('exist').then(() => {
102+
cy.wrap(registerComponent).should('be.called');
103+
});
104+
});
105+
});
87106

107+
it('should handle tabs', () => {
108+
const onChangeMethodID = cy.stub();
109+
defaultValues.onChangeMethodID = onChangeMethodID;
110+
const servoyApiSpy = defaultValues.servoyApi;
88111
const callServerSideApiSpy = cy.stub(servoyApiSpy, 'callServerSideApi');
89112

90-
cy.mount(WrapperComponent, config).then((wrapper) => {
91-
// Check if all tabs exist and have correct text
92-
cy.get('button').should('have.length', 3);
93-
cy.get('button').eq(0).should('have.text', 'tab1');
94-
cy.get('button').eq(1).should('have.text', 'tab2');
95-
cy.get('button').eq(2).should('have.text', 'tab3');
113+
cy.mount(WrapperComponent, configWrapper).then((wrapper) => {
114+
applyDefaultProps(wrapper);
115+
// Check if all tabs exist and have correct text
116+
cy.get('button').should('have.length', 3);
117+
cy.get('button').eq(0).should('have.text', 'tab1');
118+
cy.get('button').eq(1).should('have.text', 'tab2');
119+
cy.get('button').eq(2).should('have.text', 'tab3');
96120

97121
cy.get('button').eq(1).click().then(() => {
98122
cy.wrap(callServerSideApiSpy).should('be.calledWith', 'setTabIndexInternal', [2]);
99-
wrapper.component.tabIndex = 2;
123+
wrapper.component.tabIndex.set(2);
100124
wrapper.fixture.detectChanges();
101-
cy.wrap(wrapper.component.element.tabIndex).should('eq', 2);
125+
cy.wrap(wrapper.component.element.tabIndex()).should('eq', 2);
102126

103127
cy.then(() => {
104-
wrapper.component.tabIndex = 1;
128+
wrapper.component.tabIndex.set(1);
105129
wrapper.fixture.detectChanges();
106-
cy.wrap(wrapper.component.element.tabIndex).should('eq', 1);
130+
cy.wrap(wrapper.component.element.tabIndex()).should('eq', 1);
107131
});
108132
});
109-
});
110-
});
133+
});
134+
});
111135

112-
it('should handle tabs edit', () => {
113-
cy.mount(WrapperComponent, config).then((wrapper) => {
114-
wrapper.component.tabIndex = 2;
136+
it('should handle tabs edit', () => {
137+
cy.mount(WrapperComponent, configWrapper).then((wrapper) => {
138+
applyDefaultProps(wrapper);
139+
wrapper.component.tabIndex.set(2);
115140
wrapper.fixture.detectChanges();
116-
cy.wrap(wrapper.component.element.tabIndex).should('eq', 2);
117-
118-
cy.then(() => {
119-
const tab = new Tab();
120-
tab.name = 'tab4';
121-
tab.containedForm = 'form4';
122-
tab.text = 'tab4';
123-
tab.disabled = false;
124-
const tabs = wrapper.component.tabs.slice();
125-
tabs.push(tab);
126-
wrapper.component.tabs = tabs;
127-
wrapper.fixture.detectChanges();
128-
cy.get('button').should('have.length', 4);
129-
cy.get('button').eq(0).should('have.text', 'tab1');
130-
cy.get('button').eq(1).should('have.text', 'tab2');
131-
cy.get('button').eq(2).should('have.text', 'tab3');
132-
cy.get('button').eq(3).should('have.text', 'tab4');
133-
cy.wrap(wrapper.component.element.tabIndex).should('eq', 2);
134-
135-
cy.then(() => {
136-
const tabs = wrapper.component.tabs.slice();
137-
tabs.splice(1, 1);
138-
wrapper.component.tabs = tabs;
139-
wrapper.fixture.detectChanges();
140-
cy.get('button').should('have.length', 3);
141-
cy.get('button').eq(0).should('have.text', 'tab1');
142-
cy.get('button').eq(1).should('have.text', 'tab3');
143-
cy.get('button').eq(2).should('have.text', 'tab4');
144-
cy.wrap(wrapper.component.element.tabIndex).should('eq', 2);
145-
146-
cy.then(() => {
147-
const tabs = wrapper.component.tabs.slice();
148-
tabs.splice(0, 1);
149-
wrapper.component.tabs = tabs;
150-
wrapper.fixture.detectChanges();
151-
cy.get('button').should('have.length', 2);
152-
cy.get('button').eq(0).should('have.text', 'tab3');
153-
cy.get('button').eq(1).should('have.text', 'tab4');
154-
cy.wrap(wrapper.component.element.tabIndex).should('eq', 2);
155-
});
156-
});
157-
});
158-
});
159-
});
160-
});
141+
cy.wrap(wrapper.component.element.tabIndex()).should('eq', 2);
142+
143+
cy.then(() => {
144+
const tab = new Tab();
145+
tab.name = 'tab4';
146+
tab.containedForm = 'form4';
147+
tab.text = 'tab4';
148+
tab.disabled = false;
149+
const tabs = wrapper.component.tabs().slice();
150+
tabs.push(tab);
151+
wrapper.component.tabs.set(tabs);
152+
cy.get('button').should('have.length', 4);
153+
cy.get('button').eq(0).should('have.text', 'tab1');
154+
cy.get('button').eq(1).should('have.text', 'tab2');
155+
cy.get('button').eq(2).should('have.text', 'tab3');
156+
cy.get('button').eq(3).should('have.text', 'tab4');
157+
cy.wrap(wrapper.component.element.tabIndex()).should('eq', 2);
158+
159+
cy.then(() => {
160+
const tabs = wrapper.component.tabs().slice();
161+
tabs.splice(1, 1);
162+
wrapper.component.tabs.set(tabs);
163+
cy.get('button').should('have.length', 3);
164+
cy.get('button').eq(0).should('have.text', 'tab1');
165+
cy.get('button').eq(1).should('have.text', 'tab3');
166+
cy.get('button').eq(2).should('have.text', 'tab4');
167+
cy.wrap(wrapper.component.element.tabIndex()).should('eq', 2);
168+
169+
cy.then(() => {
170+
const tabs = wrapper.component.tabs().slice();
171+
tabs.splice(0, 1);
172+
wrapper.component.tabs.set(tabs);
173+
cy.get('button').should('have.length', 2);
174+
cy.get('button').eq(0).should('have.text', 'tab3');
175+
cy.get('button').eq(1).should('have.text', 'tab4');
176+
cy.wrap(wrapper.component.element.tabIndex()).should('eq', 2);
177+
});
178+
});
179+
});
180+
});
181+
});
182+
});

components/projects/bootstrapcomponents/src/bts_basefield.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ export class ServoyBootstrapBasefield<T extends HTMLElement> extends ServoyBoots
2222
readonly placeholderText = input<string>(undefined);
2323
readonly selectOnEnter = input<boolean>(undefined);
2424

25-
protected _dataProviderID = signal<any>(undefined);
26-
protected _editable = signal<boolean>(undefined);
25+
_dataProviderID = signal<any>(undefined);
26+
_editable = signal<boolean>(undefined);
2727

2828
mustExecuteOnFocus = true;
2929

@@ -57,14 +57,6 @@ export class ServoyBootstrapBasefield<T extends HTMLElement> extends ServoyBoots
5757

5858
svyOnChanges(changes: SimpleChanges) {
5959
if (changes) {
60-
/*if (changes.dataProviderID) {
61-
this._dataProviderID.set(this.dataProviderID());
62-
}
63-
64-
if (changes.editable) {
65-
this._editable.set(this.editable());
66-
}*/
67-
6860
for (const property of Object.keys(changes)) {
6961
const change = changes[property];
7062
switch (property) {

0 commit comments

Comments
 (0)