From 2898857473dd5c300f606ec300d665dd1befc1dd Mon Sep 17 00:00:00 2001 From: Jonathan Ruddell Date: Wed, 24 Nov 2021 18:14:28 -0500 Subject: [PATCH] improve e2e tests add comments delimiting fields. for blob fields, use return key instead of scrolling to content type fields. add flicker2 JDL for test dont add onSubmitEditing that throws error - can't focus on enums --- .github/workflows/app.yml | 13 ++--- .github/workflows/ios.yml | 13 ++--- .../entity/templates/entity-e2e-test.js.ejs | 46 ++++++++++++---- .../templates/entity-edit-screen.js.ejs | 6 +-- lib/entity-helpers.js | 54 +++++++++++++++---- test/jdl/entities-flickr2.jdl | 35 ++++++++++++ test/scripts/generate-react-native-app.sh | 12 ++--- 7 files changed, 139 insertions(+), 40 deletions(-) create mode 100644 test/jdl/entities-flickr2.jdl diff --git a/.github/workflows/app.yml b/.github/workflows/app.yml index 46f85f0f1..727e058ca 100644 --- a/.github/workflows/app.yml +++ b/.github/workflows/app.yml @@ -19,17 +19,18 @@ jobs: jhipster_version: [7.3.1, 6] node_version: [14.x] app_type: - - OauthDtoApp - - JwtWebsocketsApp + - JwtDtoWebsocketsApp + - OauthFlickrApp - OauthHealthPointsApp include: - - app_type: JwtWebsocketsApp + - app_type: JwtDtoWebsocketsApp auth_type: jwt - dto: false + dto: true websockets: true - - app_type: OauthDtoApp + - app_type: OauthFlickrApp auth_type: oauth2 - dto: true + dto: false + entity_jdl: entities-flickr2.jdl - app_type: OauthHealthPointsApp auth_type: oauth2 dto: false diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 71bdf974c..0e7b47f90 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -30,15 +30,12 @@ jobs: jhipster_version: [7.3.1] node_version: [14.x] app_type: - - JwtApp - JwtDtoApp - JwtWebsocketsApp - - JwtHealthPoints + - JwtHealthPointsApp + - JwtFlickrApp - OauthApp include: - - app_type: JwtApp - auth_type: jwt - dto: false - app_type: JwtDtoApp auth_type: jwt dto: true @@ -46,10 +43,14 @@ jobs: auth_type: jwt dto: false websockets: true - - app_type: JwtHealthPoints + - app_type: JwtHealthPointsApp auth_type: jwt dto: false entity_jdl: entities-21points.jdl + - app_type: JwtFlickrApp + auth_type: jwt + dto: false + entity_jdl: entities-flickr2.jdl - app_type: OauthApp auth_type: oauth2 dto: false diff --git a/generators/entity/templates/entity-e2e-test.js.ejs b/generators/entity/templates/entity-e2e-test.js.ejs index f66e3cf9e..796a9f4e7 100644 --- a/generators/entity/templates/entity-e2e-test.js.ejs +++ b/generators/entity/templates/entity-e2e-test.js.ejs @@ -69,28 +69,36 @@ describe('<%= context.entityNameCapitalized %> Screen Tests', () => { it('should allow you to create, update, and delete the <%= context.entityNameCapitalized %> entity', async () => { await expect(element(by.id('<%= context.entityInstance %>Screen'))).toBeVisible() - // create + /* + * Create <%= context.entityNameCapitalized %> + */ await tapFirstElementByLabel(' New ') await waitForElementToBeVisibleById('<%= context.entityInstance %>EditScrollView'); <%_ context.fields.filter(field => !field.id).forEach((field, index) => { _%> <%_ let formFieldType = context.getEntityFormFieldType(field); _%> + // <%= field.fieldName %> await scrollTo('<%= field.fieldName %>Input', '<%= context.entityInstance %>EditScrollView') <%_ if (formFieldType === 'text') { _%> <%_ if (field.fieldType === 'byte[]') { _%> <%_ if (field.fieldTypeBlobContent !== 'text') { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7') - await scrollTo('<%= field.fieldName %>ContentTypeInput', '<%= context.entityInstance %>EditScrollView') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() await element(by.id('<%= field.fieldName %>ContentTypeInput')).replaceText('image/gif') + await element(by.id('<%= field.fieldName %>ContentTypeInput')).tapReturnKey() <%_ } else { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('long-text-blob-content') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() <%_ } _%> <%_ } else if (field.fieldType !== 'Duration') { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('<%= createFakeData[field.fieldName] %>') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() <%_ } else { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('PT12S') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() <%_ } _%> <%_ } else if (formFieldType === 'number') { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('<%= createFakeData[field.fieldName] %>') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() <%_ } else if (formFieldType === 'date') { _%> await setDateTimePickerValue('<%= field.fieldName %>Input', '<%= new Date(createFakeData[field.fieldName]).toCustomLocalDate() %>', 'MM/dd/yy'); <%_ } else if (formFieldType === 'datetime') { _%> @@ -101,14 +109,17 @@ describe('<%= context.entityNameCapitalized %> Screen Tests', () => { await setPickerValue('<%= field.fieldName %>Input', '<%= createFakeData[field.fieldName] %>'); <%_ } _%> <%_ }) _%> - await element(by.id('<%= context.entityInstance %>EditScrollView')).swipe('down', 'slow'); + // save await scrollTo('submitButton', '<%= context.entityInstance %>EditScrollView') await waitThenTapButton('submitButton') - // view - validate the creation + /* + * View <%= context.entityNameCapitalized %> - validate the creation + */ await waitForElementToBeVisibleById('<%= context.entityInstance %>DetailScrollView'); <%_ context.fields.filter(field => !field.id).forEach((field, index) => { _%> <%_ let formFieldType = context.getEntityFormFieldType(field); _%> + // <%= field.fieldName %> await scrollTo('<%= field.fieldName %>', '<%= context.entityInstance %>DetailScrollView') <%_ if (formFieldType === 'text') { _%> <%_ if (field.fieldType === 'byte[]') { _%> @@ -137,29 +148,37 @@ describe('<%= context.entityNameCapitalized %> Screen Tests', () => { <%_ } _%> <%_ }) _%> - // update + /* + * Update <%= context.entityNameCapitalized %> + */ await scrollTo('<%= context.entityInstance %>EditButton', '<%= context.entityInstance %>DetailScrollView') await tapFirstElementByLabel('<%= context.entityNameCapitalized %> Edit Button'); await waitForElementToBeVisibleById('<%= context.entityInstance %>EditScrollView'); <%_ context.fields.filter(field => !field.id).forEach((field, index) => { _%> <%_ let formFieldType = context.getEntityFormFieldType(field); _%> + // <%= field.fieldName %> await scrollTo('<%= field.fieldName %>Input', '<%= context.entityInstance %>EditScrollView') <%_ if (formFieldType === 'text') { _%> <%_ if (field.fieldType === 'byte[]') { _%> <%_ if (field.fieldTypeBlobContent !== 'text') { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7') - await scrollTo('<%= field.fieldName %>ContentTypeInput', '<%= context.entityInstance %>EditScrollView') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() await element(by.id('<%= field.fieldName %>ContentTypeInput')).replaceText('image/gif') + await element(by.id('<%= field.fieldName %>ContentTypeInput')).tapReturnKey() <%_ } else { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('long-text-blob-content-2') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() <%_ } _%> <%_ } else if (field.fieldType !== 'Duration') { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('<%= createFakeData[field.fieldName] %>') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() <%_ } else { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('PT13S') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() <%_ } _%> <%_ } else if (formFieldType === 'number') { _%> await element(by.id('<%= field.fieldName %>Input')).replaceText('<%= updateFakeData[field.fieldName] %>') + await element(by.id('<%= field.fieldName %>Input')).tapReturnKey() <%_ } else if (formFieldType === 'date') { _%> await setDateTimePickerValue('<%= field.fieldName %>Input', '<%= new Date(updateFakeData[field.fieldName]).toCustomLocalDate() %>', 'MM/dd/yy'); <%_ } else if (formFieldType === 'datetime') { _%> @@ -170,14 +189,17 @@ describe('<%= context.entityNameCapitalized %> Screen Tests', () => { await setPickerValue('<%= field.fieldName %>Input', '<%= updateFakeData[field.fieldName] %>'); <%_ } _%> <%_ }) _%> - await element(by.id('<%= context.entityInstance %>EditScrollView')).swipe('down', 'slow'); + // save await scrollTo('submitButton', '<%= context.entityInstance %>EditScrollView') await waitThenTapButton('submitButton') - // view - validate the update + /* + * View <%= context.entityNameCapitalized %> - validate the update + */ await waitForElementToBeVisibleById('<%= context.entityInstance %>DetailScrollView'); <%_ context.fields.filter(field => !field.id).forEach((field, index) => { _%> <%_ let formFieldType = context.getEntityFormFieldType(field); _%> + // <%= field.fieldName %> await scrollTo('<%= field.fieldName %>', '<%= context.entityInstance %>DetailScrollView') <%_ if (formFieldType === 'text') { _%> <%_ if (field.fieldType === 'byte[]') { _%> @@ -206,14 +228,18 @@ describe('<%= context.entityNameCapitalized %> Screen Tests', () => { <%_ } _%> <%_ }) _%> - // delete + /* + * Delete + */ await scrollTo('<%= context.entityInstance %>DeleteButton', '<%= context.entityInstance %>DetailScrollView') await waitThenTapButton('<%= context.entityInstance %>DeleteButton'); await waitForElementToBeVisibleById('<%= context.entityInstance %>DeleteModal'); await waitThenTapButton('deleteButton') await waitForElementToBeVisibleById('<%= context.entityInstance %>Screen'); - // logout + /* + * Logout + */ await goBack() await waitForElementToBeVisibleById('entityScreenScrollList'); await logout() diff --git a/generators/entity/templates/entity-edit-screen.js.ejs b/generators/entity/templates/entity-edit-screen.js.ejs index 4354b35e1..8734e8b25 100644 --- a/generators/entity/templates/entity-edit-screen.js.ejs +++ b/generators/entity/templates/entity-edit-screen.js.ejs @@ -169,11 +169,11 @@ const onSubmit = (data) => update<%= context.entityNameCapitalized %>(formValueT
validationSchema={validationSchema} <%_ } _%>onSubmit={onSubmit} ref={formRef}> <%_ context.fields.filter(field => !field.id).forEach((field, index) => { _%> <%_ - let nextFieldName = null + let nextField = null; if (index !== context.fields.filter(field => !field.id).length - 1) { - nextFieldName = context.fields.filter(field => !field.id)[index + 1].fieldName + nextField = context.fields.filter(field => !field.id)[index + 1]; } - const formField = context.getEntityFormField(field, nextFieldName, context.relationships.filter(relation => relation.ownerSide).length); + const formField = context.getEntityFormField(field, nextField, context.relationships.filter(relation => relation.ownerSide).length); _%> <%- formField %> <%_ }) _%> diff --git a/lib/entity-helpers.js b/lib/entity-helpers.js index 16ea117cf..f772c1e46 100644 --- a/lib/entity-helpers.js +++ b/lib/entity-helpers.js @@ -32,7 +32,15 @@ const getEntityFormFieldType = field => { return 'text'; }; -const getEntityFormFieldAttributes = (fieldType, fieldName, fieldIsEnum, nextFieldName, numRelationships) => { +const getEntityFormFieldAttributes = ( + fieldType, + fieldName, + fieldIsEnum, + nextFieldName, + nextFieldType, + nextFieldIsEnum, + numRelationships +) => { const fieldNameHumanized = _.startCase(fieldName); let attributes = ` name='${fieldName}' @@ -76,31 +84,59 @@ const getEntityFormFieldAttributes = (fieldType, fieldName, fieldIsEnum, nextFie `; } - if (nextFieldName) { + if (nextFieldName && !nextFieldIsEnum) { attributes += ` onSubmitEditing={() => ${nextFieldName}Ref.current?.focus()} `; } else if (numRelationships === 0) { - attributes += ` - onSubmitEditing={() => formRef.current?.submitForm()} - `; + // todo: commented out to help with e2e tests scrolling issues + // attributes += ` + // onSubmitEditing={() => formRef.current?.submitForm()} + // `; } return attributes; }; -const getEntityFormField = (field, nextFieldName, numRelationships) => { +const getEntityFormField = (field, nextField, numRelationships) => { const fieldType = field.fieldType; const fieldName = field.fieldName; const fieldIsEnum = field.fieldIsEnum; + const nextFieldName = nextField ? nextField.fieldName : null; + const nextFieldType = nextField ? nextField.fieldType : null; + const nextFieldIsEnum = nextField ? nextField.fieldIsEnum : null; if (field.fieldType === 'byte[]' && field.fieldTypeBlobContent !== 'text') { // need to add a contentType input for blobs - const attributes = getEntityFormFieldAttributes(fieldType, fieldName, fieldIsEnum, `${fieldName}ContentType`, numRelationships); - const attributesContentType = getEntityFormFieldAttributes('String', `${fieldName}ContentType`, false, nextFieldName, numRelationships); + const attributes = getEntityFormFieldAttributes( + fieldType, + fieldName, + fieldIsEnum, + `${fieldName}ContentType`, + 'String', + false, + numRelationships + ); + const attributesContentType = getEntityFormFieldAttributes( + 'String', + `${fieldName}ContentType`, + false, + nextFieldName, + nextFieldType, + false, + numRelationships + ); return ` `; } - const attributes = getEntityFormFieldAttributes(fieldType, fieldName, fieldIsEnum, nextFieldName, numRelationships); + const attributes = getEntityFormFieldAttributes( + fieldType, + fieldName, + fieldIsEnum, + nextFieldName, + nextFieldType, + nextFieldIsEnum, + numRelationships + ); return ``; }; diff --git a/test/jdl/entities-flickr2.jdl b/test/jdl/entities-flickr2.jdl new file mode 100644 index 000000000..da562649a --- /dev/null +++ b/test/jdl/entities-flickr2.jdl @@ -0,0 +1,35 @@ +/* + * This is the application and entity model for the Flickr app (https://github.com/mraible/mobile-jhipster/) application from Matt Raible + */ + +entity Album { + title String required + description TextBlob + created Instant +} + +entity Photo { + title String required + description TextBlob + image ImageBlob required + height Integer + width Integer + taken Instant + uploaded Instant +} + +entity Tag { + name String required minlength(2) +} + +relationship ManyToOne { + Album{user(login)} to User + Photo{album(title)} to Album +} + +relationship ManyToMany { + Photo{tag(name)} to Tag{photo} +} + +paginate Album with pagination +paginate Photo, Tag with infinite-scroll diff --git a/test/scripts/generate-react-native-app.sh b/test/scripts/generate-react-native-app.sh index e9cea17d0..1d61abcac 100755 --- a/test/scripts/generate-react-native-app.sh +++ b/test/scripts/generate-react-native-app.sh @@ -6,15 +6,15 @@ rm -rf ../${JHI_REACT_NATIVE_APP_NAME} && mkdir ../${JHI_REACT_NATIVE_APP_NAME} echo "Using JDL for Generation" -# todo: debug fix for why --blueprints flag no longer works +# todo: debug fix for why --blueprints flag no longer works for jhipster v7.4.0+ # generate the app using the same JDL as the backend -#if [ "$JHIPSTER_VERSION" = "6" ]; then +if [ "$JHIPSTER_VERSION" = "6" ]; then rnhipster jdl ../${JHI_REACT_NATIVE_APP_NAME}.jdl \ --defaults --no-insight --skip-git -#else -# jhipster --blueprints react-native jdl ../${JHI_REACT_NATIVE_APP_NAME}.jdl \ -# --defaults --no-insight --skip-git -#fi +else + jhipster --blueprints react-native jdl ../${JHI_REACT_NATIVE_APP_NAME}.jdl \ + --defaults --no-insight --skip-git +fi # list files ls -al