@@ -13,9 +13,18 @@ describe('FlowFuse - Personal Access Tokens', () => {
1313 cy . get ( '[data-action="new-token"]' ) . click ( )
1414 cy . get ( '[data-el="add-token-dialog"]' ) . should ( 'be.visible' )
1515
16- // expiry disabled by default
16+ // expiry unchecked and date field hidden by default
1717 cy . get ( '[data-form="expiry-toggle"] input' ) . should ( 'not.be.checked' )
18- cy . get ( '[data-form="token-expiry"] input' ) . should ( 'be.disabled' )
18+ cy . get ( '[data-form="token-expiry"]' ) . should ( 'not.exist' )
19+
20+ // read-only unchecked by default
21+ cy . get ( '[data-form="readonly-toggle"] input' ) . should ( 'not.be.checked' )
22+
23+ // admin opt-in unchecked by default (alice is admin so it should be visible)
24+ cy . get ( '[data-form="admin-optin-toggle"] input' ) . should ( 'not.be.checked' )
25+
26+ // team scope warning visible when no teams selected
27+ cy . contains ( 'This token will have access to all teams you belong to' ) . should ( 'be.visible' )
1928
2029 cy . get ( '[data-el="add-token-dialog"]' ) . within ( ( ) => {
2130 // check primary is disabled by default
@@ -30,6 +39,22 @@ describe('FlowFuse - Personal Access Tokens', () => {
3039 cy . get ( '[data-el="add-token-dialog"]' ) . should ( 'not.be.visible' )
3140 } )
3241
42+ it ( 'expiry date field appears when expiry is toggled on' , ( ) => {
43+ cy . get ( '[data-action="new-token"]' ) . click ( )
44+
45+ // date field should not exist initially
46+ cy . get ( '[data-form="token-expiry"]' ) . should ( 'not.exist' )
47+
48+ // toggle expiry on
49+ cy . get ( '[data-form="expiry-toggle"]' ) . click ( )
50+ cy . get ( '[data-form="token-expiry"]' ) . should ( 'exist' )
51+ cy . get ( '[data-form="token-expiry"] input' ) . should ( 'not.be.disabled' )
52+
53+ // toggle expiry off
54+ cy . get ( '[data-form="expiry-toggle"]' ) . click ( )
55+ cy . get ( '[data-form="token-expiry"]' ) . should ( 'not.exist' )
56+ } )
57+
3358 it ( 'can be added without an expiry' , ( ) => {
3459 const TOKEN_NAME = 'Token 1'
3560 // count how many tokens we already have
@@ -89,6 +114,66 @@ describe('FlowFuse - Personal Access Tokens', () => {
89114 cy . get ( '[data-el="tokens-table"] tbody' ) . find ( 'tr' ) . last ( ) . should ( 'contain' , '2050' )
90115 } )
91116
117+ it ( 'can be added with read-only enabled' , ( ) => {
118+ cy . intercept ( 'POST' , '/api/*/user/tokens' ) . as ( 'addPersonalAccessToken' )
119+
120+ cy . get ( '[data-action="new-token"]' ) . click ( )
121+ cy . get ( '[data-form="token-name"] input' ) . type ( 'ReadOnly Token' )
122+ cy . get ( '[data-form="readonly-toggle"]' ) . click ( )
123+
124+ cy . get ( '[data-el="add-token-dialog"] [data-action="dialog-confirm"]' ) . click ( )
125+
126+ cy . wait ( '@addPersonalAccessToken' ) . its ( 'request.body' ) . should ( 'have.property' , 'readOnly' , true )
127+
128+ cy . get ( '[data-el="add-token-confirmation"]' ) . should ( 'be.visible' )
129+ cy . get ( '[data-el="add-token-confirmation"] [data-action="token-confirmation-done"]' ) . click ( )
130+
131+ // token list should show Read Only badge
132+ cy . get ( '[data-el="tokens-table"] tbody' ) . find ( 'tr' ) . last ( ) . should ( 'contain' , 'Read Only' )
133+ } )
134+
135+ it ( 'can be added with team scope' , ( ) => {
136+ cy . intercept ( 'POST' , '/api/*/user/tokens' ) . as ( 'addPersonalAccessToken' )
137+
138+ cy . get ( '[data-action="new-token"]' ) . click ( )
139+ cy . get ( '[data-form="token-name"] input' ) . type ( 'Team Scoped Token' )
140+
141+ // select the first team
142+ cy . get ( '[data-form^="team-scope-"]' ) . first ( ) . click ( )
143+
144+ // warning should disappear when a team is selected
145+ cy . contains ( 'This token will have access to all teams you belong to' ) . should ( 'not.exist' )
146+
147+ cy . get ( '[data-el="add-token-dialog"] [data-action="dialog-confirm"]' ) . click ( )
148+
149+ cy . wait ( '@addPersonalAccessToken' ) . its ( 'request.body' ) . should ( 'have.property' , 'teamIds' )
150+
151+ cy . get ( '[data-el="add-token-confirmation"]' ) . should ( 'be.visible' )
152+ cy . get ( '[data-el="add-token-confirmation"] [data-action="token-confirmation-done"]' ) . click ( )
153+
154+ // token list should show Team Scoped
155+ cy . get ( '[data-el="tokens-table"] tbody' ) . find ( 'tr' ) . last ( ) . should ( 'contain' , 'Team Scoped' )
156+ } )
157+
158+ it ( 'can be added with admin opt-in' , ( ) => {
159+ cy . intercept ( 'POST' , '/api/*/user/tokens' ) . as ( 'addPersonalAccessToken' )
160+
161+ cy . get ( '[data-action="new-token"]' ) . click ( )
162+ cy . get ( '[data-form="token-name"] input' ) . type ( 'Admin Token' )
163+ cy . get ( '[data-form="admin-optin-toggle"]' ) . click ( )
164+
165+ cy . get ( '[data-el="add-token-dialog"] [data-action="dialog-confirm"]' ) . click ( )
166+
167+ cy . wait ( '@addPersonalAccessToken' ) . its ( 'request.body' ) . should ( 'have.property' , 'adminOptIn' , true )
168+
169+ cy . get ( '[data-el="add-token-confirmation"]' ) . should ( 'be.visible' )
170+ cy . get ( '[data-el="add-token-confirmation"] [data-action="token-confirmation-done"]' ) . click ( )
171+ } )
172+
173+ it ( 'token list shows All Teams for unscoped tokens' , ( ) => {
174+ cy . get ( '[data-el="tokens-table"] tbody' ) . find ( 'tr' ) . first ( ) . should ( 'contain' , 'All Teams' )
175+ } )
176+
92177 it ( 'can be removed' , ( ) => {
93178 // count how many tokens we already have
94179 const rows = Cypress . $ ( '[data-el="tokens-table"] tbody' ) . find ( 'tr.ff-data-table--row' ) . length
0 commit comments