glib-web 4.44.6 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/.github/workflows/lint.yml +2 -2
  2. package/.nycrc.json +3 -1
  3. package/README.md +1 -0
  4. package/components/charts/series.js +23 -11
  5. package/components/component.vue +0 -5
  6. package/components/fields/checkGroup.vue +14 -7
  7. package/components/fields/richText2.vue +33 -3
  8. package/components/fields/upload.vue +5 -3
  9. package/components/mixins/styles.js +0 -1
  10. package/components/popover.vue +107 -78
  11. package/cypress/e2e/glib-web/auth.cy.ts +21 -0
  12. package/cypress/e2e/glib-web/dialog.cy.ts +39 -1
  13. package/cypress/e2e/glib-web/dirtyState.cy.ts +8 -23
  14. package/cypress/e2e/glib-web/fieldsCreditCard.cy.ts +22 -0
  15. package/cypress/e2e/glib-web/fieldsDateTime.cy.ts +48 -0
  16. package/cypress/e2e/glib-web/fieldsLocation.cy.ts +40 -0
  17. package/cypress/e2e/glib-web/fieldsOtp.cy.ts +68 -0
  18. package/cypress/e2e/glib-web/fieldsPhone.cy.ts +87 -0
  19. package/cypress/e2e/glib-web/fieldsRating.cy.ts +91 -0
  20. package/cypress/e2e/glib-web/fieldsRichText.cy.ts +137 -0
  21. package/cypress/e2e/glib-web/fieldsStripeToken.cy.ts +47 -0
  22. package/cypress/e2e/glib-web/fieldsUpload.cy.ts +111 -0
  23. package/cypress/e2e/glib-web/window.cy.ts +13 -6
  24. package/cypress/e2e/glib-web/windows.cy.ts +33 -1
  25. package/cypress/helper.ts +13 -1
  26. package/cypress/support/component.ts +15 -0
  27. package/cypress/support/e2e.ts +15 -0
  28. package/package.json +1 -1
  29. package/components/composable/dropable.js +0 -52
  30. package/components/fields/googlePlace.vue +0 -162
  31. package/components/mixins/tooltip.js +0 -57
  32. package/cypress/e2e/glib-web/multiupload.cy.ts +0 -25
@@ -0,0 +1,48 @@
1
+ import { testPageUrl, withComponent } from "../../helper"
2
+
3
+ const url = testPageUrl('fields_date_time')
4
+
5
+ describe('fields_date_time', () => {
6
+ it('updates date actions', () => {
7
+ cy.visit(url)
8
+
9
+ cy.contains('Set today + 1 week').click()
10
+ cy.get('#date_status').should('contain.text', 'Date changed')
11
+
12
+ cy.contains('Clear date').click()
13
+ cy.get('#date_status').should('contain.text', 'Date changed')
14
+ cy.get('input[name="user[date_basic]"]').should('have.value', '')
15
+ })
16
+
17
+ it('updates datetime actions', () => {
18
+ cy.visit(url)
19
+
20
+ cy.contains('Set datetime (evening)').click()
21
+ cy.get('#datetime_status').should('contain.text', 'Datetime changed')
22
+ cy.get('input[name="user[datetime_basic]"]').should('have.value', '2024-12-12T18:45')
23
+
24
+ cy.contains('Clear datetime').click()
25
+ cy.get('#datetime_status').should('contain.text', 'Datetime changed')
26
+ cy.get('input[name="user[datetime_basic]"]').should('have.value', '')
27
+ })
28
+
29
+ it('toggles templates and disabled state', () => {
30
+ cy.visit(url)
31
+
32
+ cy.contains('Disable date').click()
33
+ cy.get('#date_basic').find('.v-input--disabled').should('exist')
34
+
35
+ cy.contains('Enable date').click()
36
+ cy.get('#date_basic').find('.v-input--disabled').should('not.exist')
37
+
38
+ cy.contains('Use text template').click()
39
+ withComponent('datetime_plain', (comp) => {
40
+ expect(comp.spec.template.type).to.eq('text')
41
+ })
42
+
43
+ cy.contains('Restore plain template').click()
44
+ withComponent('datetime_plain', (comp) => {
45
+ expect(comp.spec.template.type).to.eq('plain')
46
+ })
47
+ })
48
+ })
@@ -0,0 +1,40 @@
1
+ import { testPageUrl } from "../../helper"
2
+
3
+ const url = testPageUrl('fields_location')
4
+
5
+ describe('fields_location', () => {
6
+ // it('shows autocomplete suggestions', () => {
7
+ // cy.visit(url)
8
+
9
+ // cy.window().its('google').should('exist')
10
+
11
+ // cy.get('input[name="user[address]"]').clear().type('Sydney')
12
+
13
+ // cy.get('.pac-container', { timeout: 10000 }).should('be.visible')
14
+ // cy.get('.pac-container .pac-item').its('length').should('be.gt', 0)
15
+ // })
16
+
17
+ it('updates the zoom field', () => {
18
+ cy.visit(url)
19
+
20
+ cy.get('input[name="user[zoom]"]').clear().type('10')
21
+ cy.get('input[name="user[zoom]"]').should('have.value', '10')
22
+ })
23
+
24
+ it('submits the form', () => {
25
+ cy.visit(url)
26
+
27
+ cy.contains('Submit').click()
28
+
29
+ cy.get('body').then(($body) => {
30
+ if ($body.find('.v-dialog').length) {
31
+ cy.get('.v-dialog').should('contain.text', 'Method: POST')
32
+ return
33
+ }
34
+
35
+ if ($body.find('.unformatted').length) {
36
+ cy.get('.unformatted').should('contain.text', 'Method: POST')
37
+ }
38
+ })
39
+ })
40
+ })
@@ -0,0 +1,68 @@
1
+ import { testPageUrl, withComponent } from "../../helper"
2
+
3
+ const url = testPageUrl('fields_otp')
4
+
5
+ describe('fields_otp', () => {
6
+ it('switches otp variants', () => {
7
+ cy.visit(url)
8
+
9
+ cy.contains('Length 4 (text)').click()
10
+ withComponent('otp_basic', (comp) => {
11
+ expect(comp.spec.length).to.eq(4)
12
+ expect(comp.spec.type).to.eq('text')
13
+ expect(comp.fieldModel).to.eq('ABCD')
14
+ })
15
+ cy.get('#otp_variant_status').should('contain.text', 'Variant: 4 digits (text)')
16
+
17
+ cy.contains('Length 6 (number)').click()
18
+ withComponent('otp_basic', (comp) => {
19
+ expect(comp.spec.length).to.eq(6)
20
+ expect(comp.spec.type).to.eq('number')
21
+ expect(comp.fieldModel).to.eq('123456')
22
+ })
23
+ cy.get('#otp_variant_status').should('contain.text', 'Variant: 6 digits (number)')
24
+
25
+ cy.contains('Length 8 (text)').click()
26
+ withComponent('otp_basic', (comp) => {
27
+ expect(comp.spec.length).to.eq(8)
28
+ expect(comp.spec.type).to.eq('text')
29
+ expect(comp.fieldModel).to.eq('A1B2C3D4')
30
+ })
31
+ cy.get('#otp_variant_status').should('contain.text', 'Variant: 8 digits (text)')
32
+ })
33
+
34
+ it('updates status actions', () => {
35
+ cy.visit(url)
36
+
37
+ cy.contains('Autofill code').click()
38
+ withComponent('otp_basic', (comp) => {
39
+ expect(comp.fieldModel).to.eq('654321')
40
+ })
41
+ cy.get('#otp_status').should('contain.text', 'Status: code changed')
42
+
43
+ cy.contains('Clear code').click()
44
+ withComponent('otp_basic', (comp) => {
45
+ expect(comp.fieldModel).to.eq('')
46
+ })
47
+ cy.get('#otp_status').should('contain.text', 'Status: code changed')
48
+ })
49
+
50
+ it('toggles disabled and clears value', () => {
51
+ cy.visit(url)
52
+
53
+ cy.contains('Disable field').click()
54
+ withComponent('otp_basic', (comp) => {
55
+ expect(comp.spec.disabled).to.eq(true)
56
+ })
57
+
58
+ cy.contains('Enable field').click()
59
+ withComponent('otp_basic', (comp) => {
60
+ expect(comp.spec.disabled).to.not.eq(true)
61
+ })
62
+
63
+ cy.contains('Clear value').click()
64
+ withComponent('otp_basic', (comp) => {
65
+ expect(comp.fieldModel).to.eq('')
66
+ })
67
+ })
68
+ })
@@ -0,0 +1,87 @@
1
+ import { testPageUrl, withComponent } from "../../helper"
2
+
3
+ const url = testPageUrl('fields_phone')
4
+
5
+ describe('fields_phone', () => {
6
+ it('switches variants', () => {
7
+ cy.visit(url)
8
+
9
+ cy.contains('Auto-detect (default)').click()
10
+ withComponent('phone_basic', (comp) => {
11
+ expect(comp.spec.disableAutoDetect).to.not.eq(true)
12
+ expect(comp.spec.defaultCountry).to.not.eq('US')
13
+ expect(comp.spec.defaultCountry).to.not.eq('AU')
14
+ expect(comp.spec.label).to.eq('Phone number')
15
+ })
16
+ cy.get('#phone_variant_status').should('contain.text', 'Variant: auto-detect (default)')
17
+
18
+ cy.contains('Default country: US').click()
19
+ withComponent('phone_basic', (comp) => {
20
+ expect(comp.spec.disableAutoDetect).to.eq(true)
21
+ expect(comp.spec.defaultCountry).to.eq('US')
22
+ expect(comp.spec.label).to.eq('Phone (US default)')
23
+ })
24
+ cy.get('#phone_variant_status').should('contain.text', 'Variant: default country US')
25
+
26
+ cy.contains('Default country: AU').click()
27
+ withComponent('phone_basic', (comp) => {
28
+ expect(comp.spec.disableAutoDetect).to.eq(true)
29
+ expect(comp.spec.defaultCountry).to.eq('AU')
30
+ expect(comp.spec.label).to.eq('Phone (AU default)')
31
+ })
32
+ cy.get('#phone_variant_status').should('contain.text', 'Variant: default country AU')
33
+ })
34
+
35
+ it('updates values via actions', () => {
36
+ cy.visit(url)
37
+
38
+ cy.contains('Set sample number').click()
39
+ withComponent('phone_basic', (comp) => {
40
+ expect(comp.fieldModel).to.contain('+1')
41
+ })
42
+ cy.get('#phone_status').should('contain.text', 'Status: number changed')
43
+
44
+ cy.contains('Clear value').click()
45
+ withComponent('phone_basic', (comp) => {
46
+ expect(comp.fieldModel).to.eq('')
47
+ })
48
+ cy.get('#phone_status').should('contain.text', 'Status: number changed')
49
+ })
50
+
51
+ it('toggles disabled/read-only and submits', () => {
52
+ cy.visit(url)
53
+
54
+ cy.contains('Disable field').click()
55
+ withComponent('phone_basic', (comp) => {
56
+ expect(comp.spec.disabled).to.eq(true)
57
+ })
58
+
59
+ cy.contains('Enable field').click()
60
+ withComponent('phone_basic', (comp) => {
61
+ expect(comp.spec.disabled).to.not.eq(true)
62
+ })
63
+
64
+ cy.contains('Read-only').click()
65
+ withComponent('phone_basic', (comp) => {
66
+ expect(comp.spec.readOnly).to.eq(true)
67
+ })
68
+
69
+ cy.contains('Editable').click()
70
+ withComponent('phone_basic', (comp) => {
71
+ expect(comp.spec.readOnly).to.not.eq(true)
72
+ })
73
+
74
+ cy.contains('Submit').click()
75
+
76
+ cy.get('body').then(($body) => {
77
+ if ($body.find('.v-dialog').length) {
78
+ cy.get('.v-dialog').should('contain.text', 'Method: POST')
79
+ return
80
+ }
81
+
82
+ if ($body.find('.unformatted').length) {
83
+ cy.get('.unformatted').should('contain.text', 'Method: POST')
84
+ }
85
+ })
86
+ })
87
+ })
@@ -0,0 +1,91 @@
1
+ import { testPageUrl, withComponent } from "../../helper"
2
+
3
+ const url = testPageUrl('fields_rating')
4
+
5
+ describe('fields_rating', () => {
6
+ it('switches rating variants', () => {
7
+ cy.visit(url)
8
+
9
+ cy.contains('Full increments').click()
10
+ withComponent('rating_main', (comp) => {
11
+ expect(comp.spec.halfIncrements).to.not.eq(true)
12
+ expect(comp.spec.color).to.eq('primary')
13
+ expect(comp.spec.size).to.eq(24)
14
+ expect(comp.spec.readOnly).to.not.eq(true)
15
+ expect(comp.fieldModel).to.eq(4)
16
+ })
17
+ cy.get('#rating_variant_status').should('contain.text', 'Variant: full increments (primary)')
18
+
19
+ cy.contains('Half increments').click()
20
+ withComponent('rating_main', (comp) => {
21
+ expect(comp.spec.halfIncrements).to.eq(true)
22
+ expect(comp.spec.color).to.eq('secondary')
23
+ expect(comp.spec.size).to.eq(24)
24
+ expect(comp.spec.readOnly).to.not.eq(true)
25
+ expect(comp.fieldModel).to.eq(3.5)
26
+ })
27
+ cy.get('#rating_variant_status').should('contain.text', 'Variant: half increments (secondary)')
28
+
29
+ cy.contains('Large size').click()
30
+ withComponent('rating_main', (comp) => {
31
+ expect(comp.spec.halfIncrements).to.eq(true)
32
+ expect(comp.spec.color).to.eq('ternary')
33
+ expect(comp.spec.size).to.eq(40)
34
+ expect(comp.spec.readOnly).to.not.eq(true)
35
+ expect(comp.fieldModel).to.eq(4.5)
36
+ })
37
+ cy.get('#rating_variant_status').should('contain.text', 'Variant: large size (ternary)')
38
+
39
+ cy.contains('Read only').click()
40
+ withComponent('rating_main', (comp) => {
41
+ expect(comp.spec.readOnly).to.eq(true)
42
+ expect(comp.fieldModel).to.eq(5)
43
+ })
44
+ cy.get('#rating_variant_status').should('contain.text', 'Variant: read-only')
45
+ })
46
+
47
+ it('updates rating actions', () => {
48
+ cy.visit(url)
49
+
50
+ cy.contains('Set to 2').click()
51
+ withComponent('rating_main', (comp) => {
52
+ expect(comp.fieldModel).to.eq(2)
53
+ expect(comp.spec.readOnly).to.not.eq(true)
54
+ })
55
+ cy.get('#rating_status').should('contain.text', 'Status: rating changed')
56
+
57
+ cy.contains('Set to 4.5').click()
58
+ withComponent('rating_main', (comp) => {
59
+ expect(comp.fieldModel).to.eq(4.5)
60
+ expect(comp.spec.halfIncrements).to.eq(true)
61
+ expect(comp.spec.readOnly).to.not.eq(true)
62
+ })
63
+ cy.get('#rating_status').should('contain.text', 'Status: rating changed')
64
+
65
+ cy.contains('Clear rating').click()
66
+ withComponent('rating_main', (comp) => {
67
+ expect(comp.fieldModel).to.eq('')
68
+ expect(comp.spec.readOnly).to.not.eq(true)
69
+ })
70
+ cy.get('#rating_status').should('contain.text', 'Status: rating changed')
71
+ })
72
+
73
+ it('toggles disabled and size', () => {
74
+ cy.visit(url)
75
+
76
+ cy.contains('Disable rating').click()
77
+ withComponent('rating_main', (comp) => {
78
+ expect(comp.spec.disabled).to.eq(true)
79
+ })
80
+
81
+ cy.contains('Enable rating').click()
82
+ withComponent('rating_main', (comp) => {
83
+ expect(comp.spec.disabled).to.not.eq(true)
84
+ })
85
+
86
+ cy.contains('Small size').click()
87
+ withComponent('rating_main', (comp) => {
88
+ expect(comp.spec.size).to.eq(18)
89
+ })
90
+ })
91
+ })
@@ -0,0 +1,137 @@
1
+ import { testPageUrl, withComponent } from "../../helper"
2
+
3
+ const url = testPageUrl('fields_richText')
4
+
5
+ describe('fields_richText', () => {
6
+ it('switches output variants', () => {
7
+ cy.visit(url)
8
+
9
+ cy.contains('Markdown output').click()
10
+ withComponent('rich_text_main', (comp) => {
11
+ expect(comp.spec.produce).to.eq('markdown')
12
+ expect(comp.spec.accept).to.eq('markdown')
13
+ })
14
+ cy.get('#rich_text_variant_status').should('contain.text', 'Variant: markdown output')
15
+
16
+ // cy.contains('HTML output').click()
17
+ // withComponent('rich_text_main', (comp) => {
18
+ // expect(comp.spec.produce).to.eq('html')
19
+ // expect(comp.spec.accept).to.eq('html')
20
+ // })
21
+ // cy.get('#rich_text_variant_status').should('contain.text', 'Variant: HTML output')
22
+
23
+ cy.contains('No uploader').click()
24
+ withComponent('rich_text_main', (comp) => {
25
+ expect(comp.spec.imageUploader).to.not.exist
26
+ })
27
+ cy.get('#rich_text_variant_status').should('contain.text', 'Variant: uploader removed')
28
+
29
+ cy.contains('Restore uploader').click()
30
+ withComponent('rich_text_main', (comp) => {
31
+ expect(comp.spec.imageUploader).to.exist
32
+ })
33
+ cy.get('#rich_text_variant_status').should('contain.text', 'Variant: uploader restored')
34
+ })
35
+
36
+ // it('inserts template content', () => {
37
+ // cy.visit(url)
38
+
39
+ // cy.contains('Insert template').click()
40
+ // cy.get('#rich_text_status').should('contain.text', 'Status: content changed')
41
+
42
+ // cy.get('input[name="user[rich_text]"]').invoke('val').should('include', 'Quick update')
43
+ // })
44
+
45
+ it('toggles editor state', () => {
46
+ cy.visit(url)
47
+
48
+ cy.contains('Disable editor').click()
49
+ withComponent('rich_text_main', (comp) => {
50
+ expect(comp.spec.disabled).to.eq(true)
51
+ })
52
+
53
+ cy.contains('Enable editor').click()
54
+ withComponent('rich_text_main', (comp) => {
55
+ expect(comp.spec.disabled).to.not.eq(true)
56
+ })
57
+
58
+ cy.contains('Toggle debug').click()
59
+ withComponent('rich_text_main', (comp) => {
60
+ expect(comp.spec.debug).to.eq(false)
61
+ })
62
+
63
+ cy.contains('Enable debug').click()
64
+ withComponent('rich_text_main', (comp) => {
65
+ expect(comp.spec.debug).to.eq(true)
66
+ })
67
+ })
68
+
69
+ it('uploads files on drop and paste', () => {
70
+ cy.visit(url)
71
+
72
+ let uploadIndex = 0
73
+ cy.window().then((win) => {
74
+ const comp = win.GLib.component.findById('rich_text_main')
75
+ expect(comp).to.exist
76
+ const uploader = comp.spec.imageUploader
77
+
78
+ cy.intercept('POST', uploader.directUploadUrl, (req) => {
79
+ uploadIndex += 1
80
+ req.reply({
81
+ statusCode: 200,
82
+ body: {
83
+ signed_id: `signed-${uploadIndex}`,
84
+ direct_upload: {
85
+ url: `https://example.com/upload-${uploadIndex}`,
86
+ headers: { 'Content-Type': 'text/csv' }
87
+ }
88
+ }
89
+ })
90
+ }).as('directUpload')
91
+
92
+ cy.intercept('PUT', 'https://example.com/upload-*', { statusCode: 200, body: '' }).as('directUploadStore')
93
+ cy.intercept('POST', uploader.blobUrlGenerator, { statusCode: 200, body: { url: 'https://example.com/blob' } }).as('blobUrl')
94
+ })
95
+
96
+ cy.fixture('bulk_edit.csv', 'binary').then((fileContent) => {
97
+ const blob = Cypress.Blob.binaryStringToBlob(fileContent, 'text/csv')
98
+ cy.window().then((win) => {
99
+ const file = new win.File([blob], 'bulk_edit.csv', { type: 'text/csv' })
100
+ const dataTransfer = new win.DataTransfer()
101
+ dataTransfer.items.add(file)
102
+ cy.get('#rich_text_main .ql-editor').trigger('drop', { dataTransfer })
103
+ })
104
+ })
105
+
106
+ cy.wait('@directUpload')
107
+ cy.wait('@directUploadStore')
108
+ cy.wait('@blobUrl')
109
+ cy.get('input[name="user[images_attributes][]"]').should('have.length', 1)
110
+ cy.get('input[name="user[images_attributes][]"]').first().should('have.value', 'signed-1')
111
+
112
+ cy.fixture('bulk_edit.csv', 'binary').then((fileContent) => {
113
+ const blob = Cypress.Blob.binaryStringToBlob(fileContent, 'text/csv')
114
+ cy.window().then((win) => {
115
+ const file = new win.File([blob], 'bulk_edit.csv', { type: 'text/csv' })
116
+ const clipboardData = new win.DataTransfer()
117
+ clipboardData.items.add(file)
118
+ cy.get('#rich_text_main .ql-editor').trigger('paste', { clipboardData })
119
+ })
120
+ })
121
+
122
+ cy.wait('@directUpload')
123
+ cy.wait('@directUploadStore')
124
+ cy.wait('@blobUrl')
125
+ cy.get('input[name="user[images_attributes][]"]').should('have.length', 2)
126
+ cy.get('input[name="user[images_attributes][]"]').eq(1).should('have.value', 'signed-2')
127
+ })
128
+
129
+ it('shows mention list when typing a person', () => {
130
+ cy.visit(url)
131
+
132
+ cy.get('#rich_text_main .ql-editor').click().type('{end} @jo')
133
+ cy.get('.ql-mention-list-container').should('be.visible')
134
+ cy.get('.ql-mention-list-container').should('contain.text', 'John Doe')
135
+ })
136
+
137
+ })
@@ -0,0 +1,47 @@
1
+ import { testPageUrl, withComponent } from "../../helper"
2
+
3
+ const url = testPageUrl('fields_stripeToken')
4
+
5
+ describe('fields_stripeToken', () => {
6
+ it('switches style variants', () => {
7
+ cy.visit(url)
8
+
9
+ cy.contains('Default style').click()
10
+ withComponent('stripe_token_basic', (comp) => {
11
+ expect(comp.spec.styleClass).to.not.exist
12
+ expect(comp.spec.label).to.eq('Card details')
13
+ expect(comp.spec.hint).to.not.exist
14
+ })
15
+
16
+ cy.contains('Outlined').click()
17
+ withComponent('stripe_token_basic', (comp) => {
18
+ expect(comp.spec.styleClass).to.eq('outlined')
19
+ expect(comp.spec.label).to.eq('Card details')
20
+ expect(comp.spec.hint).to.not.exist
21
+ })
22
+
23
+ cy.contains('Individual').click()
24
+ withComponent('stripe_token_basic', (comp) => {
25
+ expect(comp.spec.styleClass).to.eq('individual')
26
+ expect(comp.spec.label).to.eq('Card details')
27
+ expect(comp.spec.hint).to.eq('Personal card')
28
+ })
29
+ })
30
+
31
+ it('submits the form', () => {
32
+ cy.visit(url)
33
+
34
+ cy.contains('Submit').click()
35
+
36
+ cy.get('body').then(($body) => {
37
+ if ($body.find('.v-dialog').length) {
38
+ cy.get('.v-dialog').should('contain.text', 'Method: POST')
39
+ return
40
+ }
41
+
42
+ if ($body.find('.unformatted').length) {
43
+ cy.get('.unformatted').should('contain.text', 'Method: POST')
44
+ }
45
+ })
46
+ })
47
+ })
@@ -39,6 +39,117 @@ describe('fields_upload', () => {
39
39
  cy.get('@filesTrigger').should('have.been.calledOnce')
40
40
  })
41
41
 
42
+ it('handles multi progress view drag and drop uploads', () => {
43
+ const htmlUploadUrl = 'http://localhost:3000/glib/json_ui_garage?path=forms%2Ffile_upload_new&mode=html'
44
+ let uploadIndex = 0
45
+ const pngBase64 =
46
+ 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNgYAAAAAMAASsJTYQAAAAASUVORK5CYII='
47
+ const pngFile = {
48
+ contents: Cypress.Buffer.from(pngBase64, 'base64'),
49
+ fileName: 'upload.png',
50
+ mimeType: 'image/png'
51
+ }
52
+
53
+ cy.intercept('POST', /\/(glib\/glib_direct_uploads|rails\/active_storage\/direct_uploads)$/, (req) => {
54
+ uploadIndex += 1
55
+ req.reply({
56
+ statusCode: 200,
57
+ body: {
58
+ signed_id: `signed-${uploadIndex}`,
59
+ direct_upload: {
60
+ url: 'https://example.com/rails/active_storage/blobs/upload',
61
+ headers: {
62
+ 'Content-Type': 'text/plain'
63
+ }
64
+ }
65
+ }
66
+ })
67
+ }).as('directUploadCreate')
68
+
69
+ cy.intercept('PUT', 'https://example.com/rails/active_storage/blobs/upload', {
70
+ statusCode: 200
71
+ }).as('directUploadStore')
72
+
73
+ cy.visit(url)
74
+
75
+ cy.window()
76
+ .should((win) => {
77
+ const multiComp = getRealComponent(win, win.GLib.component.findById('fields_upload_multiprogress'))
78
+ expect(multiComp, 'multi progress component').to.exist
79
+ expect(multiComp.$el, 'multi progress element').to.exist
80
+ expect(multiComp.$el.querySelector('.gdrop-file'), 'multi progress dropzone').to.exist
81
+ })
82
+ .then((win) => {
83
+ const multiComp = getRealComponent(win, win.GLib.component.findById('fields_upload_multiprogress'))
84
+ cy.wrap(multiComp.$el).as('multiRoot')
85
+ cy.wrap(multiComp.$el.querySelector('.gdrop-file')).as('dropzone')
86
+ })
87
+
88
+ cy.get('@dropzone').should('have.class', 'border-[2px]')
89
+ cy.get('@dropzone').trigger('drag')
90
+ cy.get('@dropzone').trigger('dragover')
91
+ cy.get('@dropzone').should('have.class', 'border-[4px]').and('not.have.class', 'border-[2px]')
92
+ cy.get('@dropzone').trigger('dragleave')
93
+ cy.get('@dropzone').should('have.class', 'border-[2px]')
94
+
95
+ cy.get('@dropzone').click({ force: true })
96
+ cy.get('@multiRoot').find('input[type="file"]').should('exist')
97
+
98
+ cy.get('@dropzone').selectFile(
99
+ pngFile,
100
+ { action: 'drag-drop' }
101
+ )
102
+
103
+ cy.wait('@directUploadCreate')
104
+ cy.wait('@directUploadStore')
105
+ cy.get('@multiRoot')
106
+ .find('input[type="hidden"][name="user[file_input_multiprogress][]"]')
107
+ .should('have.length', 1)
108
+
109
+ cy.get('@dropzone').selectFile(
110
+ { ...pngFile, fileName: 'second.png' },
111
+ { action: 'drag-drop' }
112
+ )
113
+
114
+ cy.wait('@directUploadCreate')
115
+ cy.wait('@directUploadStore')
116
+
117
+ cy.get('@multiRoot').find('.guploaded-file .file-container').should('have.length', 2)
118
+ cy.get('@multiRoot')
119
+ .find('input[type="hidden"][name="user[file_input_multiprogress][]"]')
120
+ .should('have.length', 2)
121
+ cy.get('@multiRoot').find('.guploaded-file .close-btn').first().click()
122
+ cy.get('@multiRoot').find('.guploaded-file .file-container').should('have.length', 1)
123
+ cy.get('@multiRoot')
124
+ .find('input[type="hidden"][name="user[file_input_multiprogress][]"]')
125
+ .should('have.length', 1)
126
+
127
+ cy.visit(htmlUploadUrl)
128
+
129
+ cy.window()
130
+ .should((win) => {
131
+ const multiComp = getRealComponent(win, win.GLib.component.findById('mp1'))
132
+ expect(multiComp, 'html multi progress component').to.exist
133
+ expect(multiComp.$el, 'html multi progress element').to.exist
134
+ expect(multiComp.$el.querySelector('.gdrop-file'), 'html multi progress dropzone').to.exist
135
+ })
136
+ .then((win) => {
137
+ const multiComp = getRealComponent(win, win.GLib.component.findById('mp1'))
138
+ cy.wrap(multiComp.$el).as('htmlMultiRoot')
139
+ cy.wrap(multiComp.$el.querySelector('.gdrop-file')).as('htmlDropzone')
140
+ })
141
+
142
+ cy.get('@htmlDropzone').selectFile(
143
+ { ...pngFile, fileName: 'html-mode.png' },
144
+ { action: 'drag-drop' }
145
+ )
146
+
147
+ cy.get('@htmlMultiRoot').find('.guploaded-file .file-container').should('have.length', 1)
148
+ cy.get('@htmlMultiRoot')
149
+ .find('input[type="hidden"][name="user[file_multiprogress1][]"]')
150
+ .should('not.exist')
151
+ })
152
+
42
153
  it('submits the form', () => {
43
154
  cy.visit(url)
44
155
 
@@ -1,14 +1,21 @@
1
1
  import { testPageUrl } from "../../helper"
2
+
2
3
  const url = testPageUrl('window')
3
4
 
4
- describe("window", () => {
5
- it('windows/open updateExisting: true', () => {
5
+ describe('window', () => {
6
+ it('opens a new window with updateExisting', () => {
6
7
  cy.visit(url)
7
8
 
8
9
  cy.contains('windows/open updateExisting: true').click()
10
+ cy.location('href').should('contain', 'fields_upload')
11
+ })
12
+
13
+ it('closes the current window', () => {
14
+ const previousUrl = testPageUrl('fields_upload')
15
+
16
+ cy.visit(previousUrl)
17
+ cy.visit(url)
9
18
 
10
- cy.location().should((loc) => {
11
- expect(loc.href).to.eq(testPageUrl('multiupload'))
12
- })
19
+ cy.contains('windows/close').click()
13
20
  })
14
- })
21
+ })