From 419ac9c8f3a821934667fb6ae0f3d46b270e8a89 Mon Sep 17 00:00:00 2001 From: Aswin M Prabhu Date: Mon, 16 Jul 2018 12:16:16 +0530 Subject: [PATCH 01/10] improve console relationships test (#130) --- README.md | 16 +- cli/cli.go | 2 +- cli/commands/console.go | 12 +- cli/commands/metadata.go | 7 +- cli/commands/metadata_apply.go | 2 +- cli/commands/metadata_apply_test.go | 8 +- cli/commands/metadata_export.go | 2 +- cli/commands/metadata_export_test.go | 8 +- cli/commands/metadata_reset.go | 2 +- cli/commands/metadata_reset_test.go | 8 +- cli/commands/migrate_test.go | 42 +-- cli/migrate/api/metadata.go | 11 +- cli/migrate/migrate.go | 15 +- .../integration/api-explorer/graphql/spec.js | 8 + .../integration/api-explorer/graphql/test.js | 3 +- .../integration/data/relationships/spec.js | 338 ++++-------------- .../integration/data/relationships/test.js | 5 + .../cypress/integration/data/views/spec.js | 2 +- .../Services/Data/TableModify/ModifyTable.js | 3 + .../Data/TableRelationships/Relationships.js | 23 +- .../TableRelationships/RelationshipsView.js | 15 +- .../src-lib/Hasura/GraphQL/Resolve/BoolExp.hs | 18 +- server/src-lib/Hasura/GraphQL/Schema.hs | 3 +- server/src-lib/Hasura/RQL/GBoolExp.hs | 17 +- 24 files changed, 225 insertions(+), 345 deletions(-) diff --git a/README.md b/README.md index e4d4b78d5455c..cf0571861a454 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,19 @@ # Hasura GraphQL Engine [![Docs](https://img.shields.io/badge/docs-v1.0-brightgreen.svg?style=flat)](https://docs.hasura.io) -[![Release](https://img.shields.io/github/release/hasura/graphql-engine/all.svg?style=flat)](https://github.com/hasura/graphql-engine/releases) + [![CircleCI](https://circleci.com/gh/hasura/graphql-engine.svg?style=shield)](https://circleci.com/gh/hasura/graphql-engine) -[![Docker pull](https://img.shields.io/docker/pulls/hasura/graphql-engine.svg?style=flat)](https://hub.docker.com/r/hasura/graphql-engine/) -![Docker image size](https://img.shields.io/microbadger/image-size/hasura/graphql-engine/latest.svg) -[![Chat on Discord](https://img.shields.io/discord/407792526867693568.svg?logo=discord&style=flat)](https://discord.gg/AnmPAz3) -[![Follow on Twitter](https://img.shields.io/twitter/follow/HasuraHQ.svg?style=flat&logo=twitter)](https://twitter.com/intent/follow?screen_name=HasuraHQ) + + + ![Hasura GraphQL Engine Banner](assets/banner.png) Hasura GraphQL Engine is a performant GraphQL server that provides **ready-to-use GraphQL API over Postgres** by auto-generating GraphQL schema and corresponding resolvers. * **Make powerful queries**: built-in filtering, pagination, and pattern search arguments and operators -* **Works with existing database**: point it to an existing, living Postgres database to instantly get a ready-to-use GraphQL API +* **Works with existing database**: point it to an existing Postgres database to instantly get a ready-to-use GraphQL API * **Fine-grained access control**: dynamic access control that integrates with your Auth * **Light-weight & performant**: ~15MB docker image; ~50MB RAM @ 1000 req/s; multi-core aware * **Dev friendly**: admin UI & Rails-inspired schema migrations @@ -58,10 +57,7 @@ GraphQL Engine provides an HTTP API. This means you can use any client-side tool ## Community -Please join our amazing community of developers and contributors: - -- [Discord](https://discord.gg/vBPpJkS) -- [Twitter](https://twitter.com/hasurahq) +Please join our amazing community of developers and contributors on [Discord](https://discord.gg/vBPpJkS). ## Support & Troubleshooting diff --git a/cli/cli.go b/cli/cli.go index 941d62a2590c6..1521ddf72291a 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -174,7 +174,7 @@ func (ec *ExecutionContext) Validate() error { // set names of files and directories ec.MigrationDir = filepath.Join(ec.ExecutionDirectory, "migrations") ec.ConfigFile = filepath.Join(ec.ExecutionDirectory, "config.yaml") - ec.MetadataFile = filepath.Join(ec.ExecutionDirectory, "metadata.yaml") + ec.MetadataFile = filepath.Join(ec.MigrationDir, "metadata.yaml") // read config and parse the values into Config err = ec.readConfig() diff --git a/cli/commands/console.go b/cli/commands/console.go index 7f03ad422057d..24e33ab601e87 100644 --- a/cli/commands/console.go +++ b/cli/commands/console.go @@ -85,7 +85,7 @@ func (o *consoleOptions) run() error { r, } - router.setRoutes(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.MigrationDir, o.EC.Logger) + router.setRoutes(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.MigrationDir, o.EC.MetadataFile, o.EC.Logger) if o.EC.Version == nil { return errors.New("cannot validate version, object is nil") @@ -152,7 +152,7 @@ type consoleRouter struct { *gin.Engine } -func (router *consoleRouter) setRoutes(nurl *url.URL, accessKey, migrationDir string, logger *logrus.Logger) { +func (router *consoleRouter) setRoutes(nurl *url.URL, accessKey, migrationDir, metadataFile string, logger *logrus.Logger) { apis := router.Group("/apis") { apis.Use(setLogger(logger)) @@ -170,6 +170,7 @@ func (router *consoleRouter) setRoutes(nurl *url.URL, accessKey, migrationDir st // Migrate api endpoints and middleware metadataAPIs := apis.Group("/metadata") { + metadataAPIs.Use(setMetadataFile(metadataFile)) metadataAPIs.Any("", api.MetadataAPI) } } @@ -192,6 +193,13 @@ func setFilePath(dir string) gin.HandlerFunc { } } +func setMetadataFile(file string) gin.HandlerFunc { + return func(c *gin.Context) { + c.Set("metadataFile", file) + c.Next() + } +} + func setLogger(logger *logrus.Logger) gin.HandlerFunc { return func(c *gin.Context) { c.Set("logger", logger) diff --git a/cli/commands/metadata.go b/cli/commands/metadata.go index 7255fd09a7601..586087d7597e7 100644 --- a/cli/commands/metadata.go +++ b/cli/commands/metadata.go @@ -3,7 +3,6 @@ package commands import ( "encoding/json" "io/ioutil" - "path/filepath" "github.com/ghodss/yaml" "github.com/hasura/graphql-engine/cli" @@ -39,7 +38,7 @@ func NewMetadataCmd(ec *cli.ExecutionContext) *cobra.Command { return metadataCmd } -func executeMetadata(cmd string, t *migrate.Migrate, metadata string) error { +func executeMetadata(cmd string, t *migrate.Migrate, metadataPath string) error { switch cmd { case "export": metaData, err := t.ExportMetadata() @@ -57,7 +56,7 @@ func executeMetadata(cmd string, t *migrate.Migrate, metadata string) error { return err } - err = ioutil.WriteFile(filepath.Join(metadata, "metadata.yaml"), data, 0644) + err = ioutil.WriteFile(metadataPath, data, 0644) if err != nil { return errors.Wrap(err, "cannot save metadata") } @@ -67,7 +66,7 @@ func executeMetadata(cmd string, t *migrate.Migrate, metadata string) error { return errors.Wrap(err, "Cannot reset Metadata") } case "apply": - data, err := ioutil.ReadFile(filepath.Join(metadata, "metadata.yaml")) + data, err := ioutil.ReadFile(metadataPath) if err != nil { return errors.Wrap(err, "cannot read metadata file") } diff --git a/cli/commands/metadata_apply.go b/cli/commands/metadata_apply.go index 26486990829ee..6ff5e4d952df6 100644 --- a/cli/commands/metadata_apply.go +++ b/cli/commands/metadata_apply.go @@ -36,5 +36,5 @@ func (o *metadataApplyOptions) run() error { if err != nil { return err } - return executeMetadata(o.actionType, migrateDrv, o.EC.ExecutionDirectory) + return executeMetadata(o.actionType, migrateDrv, o.EC.MetadataFile) } diff --git a/cli/commands/metadata_apply_test.go b/cli/commands/metadata_apply_test.go index 5624985dc2cb6..261d1fba585a4 100644 --- a/cli/commands/metadata_apply_test.go +++ b/cli/commands/metadata_apply_test.go @@ -10,13 +10,13 @@ import ( "github.com/sirupsen/logrus/hooks/test" ) -func testMetadataApply(t *testing.T, executionDir string, endpoint *url.URL) { +func testMetadataApply(t *testing.T, metadataFile string, endpoint *url.URL) { logger, _ := test.NewNullLogger() opts := &metadataApplyOptions{ EC: &cli.ExecutionContext{ - Logger: logger, - Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), - ExecutionDirectory: executionDir, + Logger: logger, + Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), + MetadataFile: metadataFile, Config: &cli.HasuraGraphQLConfig{ Endpoint: endpoint.String(), AccessKey: "", diff --git a/cli/commands/metadata_export.go b/cli/commands/metadata_export.go index 0c42f1790767b..e51323c595b62 100644 --- a/cli/commands/metadata_export.go +++ b/cli/commands/metadata_export.go @@ -36,5 +36,5 @@ func (o *metadataExportOptions) run() error { if err != nil { return err } - return executeMetadata(o.actionType, migrateDrv, o.EC.ExecutionDirectory) + return executeMetadata(o.actionType, migrateDrv, o.EC.MetadataFile) } diff --git a/cli/commands/metadata_export_test.go b/cli/commands/metadata_export_test.go index a58034ff6cdd5..98e8f0d21b9a5 100644 --- a/cli/commands/metadata_export_test.go +++ b/cli/commands/metadata_export_test.go @@ -10,13 +10,13 @@ import ( "github.com/sirupsen/logrus/hooks/test" ) -func testMetadataExport(t *testing.T, executionDir string, endpoint *url.URL) { +func testMetadataExport(t *testing.T, metadataFile string, endpoint *url.URL) { logger, _ := test.NewNullLogger() opts := &metadataExportOptions{ EC: &cli.ExecutionContext{ - Logger: logger, - Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), - ExecutionDirectory: executionDir, + Logger: logger, + Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), + MetadataFile: metadataFile, Config: &cli.HasuraGraphQLConfig{ Endpoint: endpoint.String(), AccessKey: "", diff --git a/cli/commands/metadata_reset.go b/cli/commands/metadata_reset.go index 6b3139c3f94cd..cce41acb0e894 100644 --- a/cli/commands/metadata_reset.go +++ b/cli/commands/metadata_reset.go @@ -37,7 +37,7 @@ func (o *metadataResetOptions) run() error { if err != nil { return err } - err = executeMetadata(o.actionType, migrateDrv, o.EC.ExecutionDirectory) + err = executeMetadata(o.actionType, migrateDrv, o.EC.MetadataFile) if err != nil { return errors.Wrap(err, "Cannot reset metadata") } diff --git a/cli/commands/metadata_reset_test.go b/cli/commands/metadata_reset_test.go index beac528285a6d..1b508dc9a2c69 100644 --- a/cli/commands/metadata_reset_test.go +++ b/cli/commands/metadata_reset_test.go @@ -10,13 +10,13 @@ import ( "github.com/sirupsen/logrus/hooks/test" ) -func testMetadataReset(t *testing.T, executionDir string, endpoint *url.URL) { +func testMetadataReset(t *testing.T, metadataFile string, endpoint *url.URL) { logger, _ := test.NewNullLogger() opts := &metadataResetOptions{ EC: &cli.ExecutionContext{ - Logger: logger, - Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), - ExecutionDirectory: executionDir, + Logger: logger, + Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), + MetadataFile: metadataFile, Config: &cli.HasuraGraphQLConfig{ Endpoint: endpoint.String(), AccessKey: "", diff --git a/cli/commands/migrate_test.go b/cli/commands/migrate_test.go index 68293c098d24f..a8677bee25825 100644 --- a/cli/commands/migrate_test.go +++ b/cli/commands/migrate_test.go @@ -93,13 +93,7 @@ func testMigrateWithDocker(t *testing.T, migrationsDir, executionDir string) { } defer os.RemoveAll(migrationsDir) - executionDir, err := ioutil.TempDir("", "") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(executionDir) - - testMigrate(t, endpointURL, migrationsDir, executionDir) + testMigrate(t, endpointURL, migrationsDir) }) }) } @@ -116,17 +110,11 @@ func TestMigrateCmd(t *testing.T) { } defer os.RemoveAll(migrationsDir) - // Create Execution Dir - executionDir, err := ioutil.TempDir("", "") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(executionDir) - - testMigrate(t, endpointURL, migrationsDir, executionDir) + testMigrate(t, endpointURL, migrationsDir) } -func testMigrate(t *testing.T, endpoint *url.URL, migrationsDir, executionDir string) { +func testMigrate(t *testing.T, endpoint *url.URL, migrationsDir string) { + metadataFile := filepath.Join(migrationsDir, "metadata.yaml") // Create 1_create_table_test.up.sql which creates table test mustWriteFile(t, migrationsDir, "1_create_table_test.up.sql", `CREATE TABLE "test"("id" serial NOT NULL, PRIMARY KEY ("id") )`) // Create 1_create_table_test.down.sql which creates table test @@ -140,6 +128,8 @@ func testMigrate(t *testing.T, endpoint *url.URL, migrationsDir, executionDir st table: test type: untrack_table `) + mustWriteFile(t, migrationsDir, "2_add_table_test.up.sql", `CREATE TABLE "author"("id" serial NOT NULL, PRIMARY KEY ("id") )`) + mustWriteFile(t, migrationsDir, "2_add_table_test.down.sql", `DROP TABLE "author";`) // Apply 1_create_table_test.up.sql testMigrateApply(t, endpoint, migrationsDir, "1", "", "", "") @@ -212,16 +202,16 @@ func testMigrate(t *testing.T, endpoint *url.URL, migrationsDir, executionDir st // Apply both 1 and 2 testMigrateApply(t, endpoint, migrationsDir, "", "", "", "") - testMetadataExport(t, executionDir, endpoint) - compareMetadata(t, executionDir, testMetadata["metadata"]) + testMetadataExport(t, metadataFile, endpoint) + compareMetadata(t, metadataFile, testMetadata["metadata"]) - testMetadataApply(t, executionDir, endpoint) - testMetadataExport(t, executionDir, endpoint) - compareMetadata(t, executionDir, testMetadata["metadata"]) + testMetadataApply(t, metadataFile, endpoint) + testMetadataExport(t, metadataFile, endpoint) + compareMetadata(t, metadataFile, testMetadata["metadata"]) - testMetadataReset(t, executionDir, endpoint) - testMetadataExport(t, executionDir, endpoint) - compareMetadata(t, executionDir, testMetadata["empty-metadata"]) + testMetadataReset(t, metadataFile, endpoint) + testMetadataExport(t, metadataFile, endpoint) + compareMetadata(t, metadataFile, testMetadata["empty-metadata"]) } func mustWriteFile(t testing.TB, dir, file string, body string) { @@ -230,8 +220,8 @@ func mustWriteFile(t testing.TB, dir, file string, body string) { } } -func compareMetadata(t testing.TB, executionDir string, actualData []byte) { - data, err := ioutil.ReadFile(filepath.Join(executionDir, "metadata.yaml")) +func compareMetadata(t testing.TB, metadataFile string, actualData []byte) { + data, err := ioutil.ReadFile(metadataFile) if err != nil { t.Fatalf("error reading metadata %s", err) } diff --git a/cli/migrate/api/metadata.go b/cli/migrate/api/metadata.go index 0d9b87d603156..ceb86901d63ed 100644 --- a/cli/migrate/api/metadata.go +++ b/cli/migrate/api/metadata.go @@ -5,7 +5,6 @@ import ( "io/ioutil" "net/http" "net/url" - "path/filepath" "strings" "github.com/ghodss/yaml" @@ -39,6 +38,12 @@ func MetadataAPI(c *gin.Context) { } logger := loggerPtr.(*logrus.Logger) + metadataFilePtr, ok := c.Get("metadataFile") + if !ok { + return + } + metadataFile := metadataFilePtr.(string) + // Create new migrate t, err := migrate.New(sourceURL.String(), databaseURL.String(), false, logger) if err != nil { @@ -84,7 +89,7 @@ func MetadataAPI(c *gin.Context) { return } - err = ioutil.WriteFile(filepath.Join(sourceURL.Path, "../metadata.yaml"), data, 0644) + err = ioutil.WriteFile(metadataFile, data, 0644) if err != nil { c.JSON(http.StatusInternalServerError, &Response{Code: "internal_error", Message: err.Error()}) return @@ -138,7 +143,7 @@ func MetadataAPI(c *gin.Context) { return } - err = ioutil.WriteFile(filepath.Join(sourceURL.Path, "../metadata.yaml"), data, 0644) + err = ioutil.WriteFile(metadataFile, data, 0644) if err != nil { c.JSON(http.StatusInternalServerError, &Response{Code: "internal_error", Message: err.Error()}) return diff --git a/cli/migrate/migrate.go b/cli/migrate/migrate.go index 2df60674656be..a343e7632b8c3 100644 --- a/cli/migrate/migrate.go +++ b/cli/migrate/migrate.go @@ -782,6 +782,7 @@ func (m *Migrate) readDown(limit int64, ret chan<- interface{}) { // to stop execution because it might have received a stop signal on the // GracefulStop channel. func (m *Migrate) runMigrations(ret <-chan interface{}) error { + var lastInsertVersion int64 for r := range ret { if m.stop() { return nil @@ -799,14 +800,18 @@ func (m *Migrate) runMigrations(ret <-chan interface{}) error { return err } - if int64(migr.Version) == migr.TargetVersion { - // Insert Version number into the table - if err := m.databaseDrv.InsertVersion(int64(migr.Version)); err != nil { - return err + version := int64(migr.Version) + if version == migr.TargetVersion { + if version != lastInsertVersion { + // Insert Version number into the table + if err := m.databaseDrv.InsertVersion(version); err != nil { + return err + } + lastInsertVersion = version } } else { // Delete Version number from the table - if err := m.databaseDrv.RemoveVersion(int64(migr.Version)); err != nil { + if err := m.databaseDrv.RemoveVersion(version); err != nil { return err } } diff --git a/console/cypress/integration/api-explorer/graphql/spec.js b/console/cypress/integration/api-explorer/graphql/spec.js index 5e58a3fdd6872..e73146c36d7c0 100644 --- a/console/cypress/integration/api-explorer/graphql/spec.js +++ b/console/cypress/integration/api-explorer/graphql/spec.js @@ -8,3 +8,11 @@ export const openAPIExplorer = () => { cy.get(getElementFromAlias('api-explorer')).click(); cy.wait(3000); }; + +export const checkExecuteQueryButton = () => { + cy.get('.execute-button'); + cy.get('.cm-def').contains('errors'); + cy.get('textarea') + .first() + .type('{enter}{uparrow}query', { force: true }); +}; diff --git a/console/cypress/integration/api-explorer/graphql/test.js b/console/cypress/integration/api-explorer/graphql/test.js index c9218ee20e8b1..b2b59c2699821 100644 --- a/console/cypress/integration/api-explorer/graphql/test.js +++ b/console/cypress/integration/api-explorer/graphql/test.js @@ -1,7 +1,7 @@ /* eslint no-unused-vars: 0 */ /* eslint import/prefer-default-export: 0 */ -import { openAPIExplorer } from './spec'; +import { openAPIExplorer, checkExecuteQueryButton } from './spec'; import { setMetaData } from '../../validators/validators'; import { testMode } from '../../../helpers/common'; @@ -21,6 +21,7 @@ const setup = () => { export const runApiExplorerTests = () => { describe('API Explorer', () => { it('Open API Explorer', openAPIExplorer); + // it('Run Query button works', checkExecuteQueryButton); }); }; diff --git a/console/cypress/integration/data/relationships/spec.js b/console/cypress/integration/data/relationships/spec.js index 8ca8807672f1d..7b2b6cae88a48 100644 --- a/console/cypress/integration/data/relationships/spec.js +++ b/console/cypress/integration/data/relationships/spec.js @@ -6,19 +6,38 @@ import { validateColumn, } from '../../validators/validators'; -export const Createtable = (name, dict) => { +const delRel = (table, relname) => { + cy.get(getElementFromAlias(table)).click(); + cy.get(getElementFromAlias('table-relationships')).click(); + cy.get(getElementFromAlias(`remove-button-${relname}`)) + .first() + .click(); + cy.on('window:alert', str => { + expect(str === 'Are you sure?').to.be.true; + }); + cy.wait(15000); +}; + +export const Createtable = (name, fields) => { + // Click on the "Add table" button and input the table name + cy.get(getElementFromAlias('sidebar-add-table')).click(); cy.url().should('eq', `${baseUrl}/data/schema/public/table/add`); cy.get(getElementFromAlias('tableName')).type(`${name}_table_rt`); - const keys = Object.keys(dict).map(k => k); - const values = Object.keys(dict).map(k => dict[k]); - for (let i = 0; i < keys.length; i += 1) { - cy.get(getElementFromAlias(`column-${i}`)).type(keys[i]); - cy.get(getElementFromAlias(`col-type-${i}`)).select(values[i]); + + // Enter column info + let i = 0; + for (const key in fields) { + if (fields.hasOwnProperty(key)) { + cy.get(getElementFromAlias(`column-${i}`)).type(key); + cy.get(getElementFromAlias(`col-type-${i}`)).select(fields[key]); + i++; + } } + // Select primary key cy.get(getElementFromAlias('primary-key-select-0')).select('id'); cy.get(getElementFromAlias('table-create')).click(); - cy.wait(10000); + cy.wait(15000); cy.url().should( 'eq', `${baseUrl}/data/schema/public/tables/${name}_table_rt/modify` @@ -28,9 +47,7 @@ export const Createtable = (name, dict) => { }; export const passRTCreateTables = () => { - cy.get(getElementFromAlias('data-create-table')).click(); Createtable('author', { id: 'Integer', name: 'Text' }); - cy.get(getElementFromAlias('sidebar-add-table')).click(); Createtable('article', { id: 'Integer', title: 'Text', @@ -38,7 +55,6 @@ export const passRTCreateTables = () => { author_id: 'Integer', rating: 'Integer', }); - cy.get(getElementFromAlias('sidebar-add-table')).click(); Createtable('comment', { id: 'Integer', user_id: 'Integer', @@ -59,7 +75,7 @@ export const Deletetable = name => { cy.on('window:alert', str => { expect(str === 'Are you sure?').to.be.true; }); - cy.wait(7000); + cy.wait(15000); validateCT(name, 'failure'); }; @@ -69,141 +85,19 @@ export const passRTDeleteTables = () => { Deletetable('author_table_rt'); }; -export const passRTAddDataarticle = data => { - cy.get(getElementFromAlias('article_table_rt')).click(); - cy.get(getElementFromAlias('table-insert-rows')).click(); - cy.get('label') - .contains('id') - .next() - .find('input') - .last() - .type(data[0]); - cy.get('label') - .contains('title') - .next() - .find('input') - .last() - .type(data[1]); - cy.get('label') - .contains('Content') - .next() - .find('input') - .last() - .type(data[2]); - cy.get('label') - .contains('author_id') - .next() - .find('input') - .last() - .type(data[3]); - cy.get('label') - .contains('rating') - .next() - .find('input') - .last() - .type(data[4]); - cy.get('button') - .contains('Save') - .click(); - cy.wait(7000); -}; - -export const passRTAddDataauthor = data => { - cy.get(getElementFromAlias('author_table_rt')).click(); - cy.get(getElementFromAlias('table-insert-rows')).click(); - cy.get('label') - .contains('id') - .next() - .find('input') - .last() - .type(data[0]); - cy.get('label') - .contains('name') - .next() - .find('input') - .last() - .type(data[1]); - cy.get(getElementFromAlias('insert-save-button')).click(); - cy.wait(7000); -}; - -export const passRTAddDatacomment = data => { - cy.get(getElementFromAlias('comment_table_rt')).click(); - cy.get(getElementFromAlias('table-insert-rows')).click(); - cy.get('label') - .contains('id') - .next() - .find('input') - .last() - .type(data[0]); - cy.get('label') - .contains('user_id') - .next() - .find('input') - .last() - .type(data[1]); - cy.get('label') - .contains('article_id') - .next() - .find('input') - .last() - .type(data[2]); - cy.get('label') - .contains('comment') - .next() - .find('input') - .last() - .type(data[3]); - cy.get(getElementFromAlias('insert-save-button')).click(); - cy.wait(7000); -}; - -export const passRTAddData = () => { - let data; - data = [1, 'A', 'Sontent', 1, 4]; - passRTAddDataarticle(data); - data = [2, 'B', 'Sontenta', 2, 4]; - passRTAddDataarticle(data); - data = [3, 'C', 'Sontentb', 1, 4]; - passRTAddDataarticle(data); - data = [1, 'A']; - passRTAddDataauthor(data); - data = [2, 'B']; - passRTAddDataauthor(data); - data = [1, 1, 1, 'new comment']; - passRTAddDatacomment(data); - data = [2, 2, 2, 'new comment']; - passRTAddDatacomment(data); - data = [3, 1, 2, 'new comment']; - passRTAddDatacomment(data); -}; - export const passRTAddManualObjRel = () => { cy.get(getElementFromAlias('article_table_rt')).click(); cy.get(getElementFromAlias('table-relationships')).click(); cy.get(getElementFromAlias('add-manual-relationship')).click(); - cy.get('select') - .first() - .select('Object Relationship'); - cy.get("input[placeholder='Enter relationship name']").type('author'); - cy.get('select') - .find('option') - .contains('Current Column') - .parent() - .select('author_id'); - cy.get('select') - .find('option') - .contains('Remote Table') - .parent() - .select('author_table_rt'); - cy.get('select') - .last() - .select('id'); + cy.get(getElementFromAlias('rel-type')).select('Object Relationship'); + cy.get(getElementFromAlias('rel-name')).type('author'); + cy.get(getElementFromAlias('current-col')).select('author_id'); + cy.get(getElementFromAlias('remote-table')).select('author_table_rt'); + cy.get(getElementFromAlias('remote-table-col')).select('id'); cy.get(getElementFromAlias('table-add-manual-relationship')) - .contains('Add') .last() .click(); - cy.wait(7000); + cy.wait(15000); validateColumn( 'article_table_rt', ['title', { name: 'author', columns: ['name'] }], @@ -215,28 +109,16 @@ export const passRTAddManualArrayRel = () => { cy.get(getElementFromAlias('article_table_rt')).click(); cy.get(getElementFromAlias('table-relationships')).click(); cy.get(getElementFromAlias('add-manual-relationship')).click(); - cy.get('select') - .first() - .select('Array Relationship'); - cy.get("input[placeholder='Enter relationship name']").type('comments'); - cy.get('select') - .find('option') - .contains('Current Column') - .parent() - .select('id'); - cy.get('select') - .find('option') - .contains('Remote Table') - .parent() - .select('comment_table_rt'); - cy.get('select') - .last() - .select('article_id'); + cy.get(getElementFromAlias('rel-type')).select('Array Relationship'); + cy.get(getElementFromAlias('rel-name')).type('comments'); + cy.get(getElementFromAlias('current-col')).select('id'); + cy.get(getElementFromAlias('remote-table')).select('comment_table_rt'); + cy.get(getElementFromAlias('remote-table-col')).select('article_id'); cy.get(getElementFromAlias('table-add-manual-relationship')) .contains('Add') .last() .click(); - cy.wait(7000); + cy.wait(15000); validateColumn( 'article_table_rt', ['title', { name: 'comments', columns: ['comment'] }], @@ -247,68 +129,38 @@ export const passRTAddManualArrayRel = () => { export const passRTAddForeignKey = () => { cy.get(getElementFromAlias('article_table_rt')).click(); cy.get(getElementFromAlias('table-modify')).click(); - cy.get('b') - .contains('author_id') - .prev() - .click(); - cy.get('[data-test=foreign-key-checkbox]').check(); - cy.get('select') - .find('option') - .contains('Reference table') - .parent() - .select('author_table_rt'); - cy.get('select') - .find('option') - .contains('Reference column') - .parent() - .select('id'); + cy.get(getElementFromAlias('edit-author_id')).click(); + cy.get(getElementFromAlias('foreign-key-checkbox')).check(); + cy.get(getElementFromAlias('ref-table')).select('author_table_rt'); + cy.get(getElementFromAlias('ref-col')).select('id'); cy.get(getElementFromAlias('save-button')).click(); - cy.wait(7000); + cy.wait(15000); cy.get(getElementFromAlias('comment_table_rt')).click(); cy.get(getElementFromAlias('table-modify')).click(); - cy.get('b') - .contains('article_id') - .prev() - .click(); - cy.get('[data-test=foreign-key-checkbox]').check(); - cy.get('select') - .find('option') - .contains('Reference table') - .parent() - .select('article_table_rt'); - cy.get('select') - .find('option') - .contains('Reference column') - .parent() - .select('id'); + cy.get(getElementFromAlias('edit-article_id')).click(); + cy.get(getElementFromAlias('foreign-key-checkbox')).check(); + cy.get(getElementFromAlias('ref-table')).select('article_table_rt'); + cy.get(getElementFromAlias('ref-col')).select('id'); cy.get(getElementFromAlias('save-button')).click(); - cy.wait(7000); + cy.wait(15000); +}; + +export const checkAddManualRelationshipsButton = () => { + cy.get(getElementFromAlias('add-rel-mod')).click(); + cy.url().should( + 'eq', + `${baseUrl}/data/schema/public/tables/comment_table_rt/relationships` + ); }; export const passRTDeleteRelationships = () => { - cy.get(getElementFromAlias('article_table_rt')).click(); - cy.get(getElementFromAlias('table-relationships')).click(); - cy.get(getElementFromAlias('remove-button')) - .first() - .click(); - cy.on('window:alert', str => { - expect(str === 'Are you sure?').to.be.true; - }); - cy.wait(7000); + delRel('article_table_rt', 'author'); validateColumn( 'article_table_rt', ['title', { name: 'author', columns: ['name'] }], 'failure' ); - cy.get(getElementFromAlias('article_table_rt')).click(); - cy.get(getElementFromAlias('table-relationships')).click(); - cy.get(getElementFromAlias('remove-button')) - .first() - .click(); - cy.on('window:alert', str => { - expect(str === 'Are you sure?').to.be.true; - }); - cy.wait(7000); + delRel('article_table_rt', 'comments'); validateColumn( 'article_table_rt', ['title', { name: 'comments', columns: ['comment'] }], @@ -319,15 +171,10 @@ export const passRTDeleteRelationships = () => { export const passRTAddSuggestedRel = () => { cy.get(getElementFromAlias('article_table_rt')).click(); cy.get(getElementFromAlias('table-relationships')).click(); - cy.get(getElementFromAlias('obj-rel-add-0')) - .contains('Add') - .last() - .click(); - cy.get('input') - .last() - .type('author'); + cy.get(getElementFromAlias('obj-rel-add-0')).click(); + cy.get(getElementFromAlias('suggested-rel-name')).type('author'); cy.get(getElementFromAlias('obj-rel-save-0')).click(); - cy.wait(7000); + cy.wait(15000); validateColumn( 'article_table_rt', ['title', { name: 'author', columns: ['name'] }], @@ -335,15 +182,10 @@ export const passRTAddSuggestedRel = () => { ); cy.get(getElementFromAlias('article_table_rt')).click(); cy.get(getElementFromAlias('table-relationships')).click(); - cy.get(getElementFromAlias('arr-rel-add-0')) - .contains('Add') - .last() - .click(); - cy.get('input') - .last() - .type('comments'); + cy.get(getElementFromAlias('arr-rel-add-0')).click(); + cy.get(getElementFromAlias('suggested-rel-name')).type('comments'); cy.get(getElementFromAlias('arr-rel-save-0')).click(); - cy.wait(7000); + cy.wait(15000); validateColumn( 'article_table_rt', ['title', { name: 'comments', columns: ['comment'] }], @@ -354,21 +196,16 @@ export const passRTAddSuggestedRel = () => { export const failRTAddSuggestedRel = () => { cy.get(getElementFromAlias('article_table_rt')).click(); cy.get(getElementFromAlias('table-relationships')).click(); - cy.get(getElementFromAlias('obj-rel-add-0')) - .contains('Add') - .last() - .click(); + cy.get(getElementFromAlias('obj-rel-add-0')).click(); cy.get(getElementFromAlias('obj-rel-save-0')).click(); // cy.get('.notification-error'); - cy.wait(7000); - cy.get('input') - .last() - .type(123123); + cy.wait(15000); + cy.get(getElementFromAlias('suggested-rel-name')).type(123123); cy.get('button') .contains('Save') .click(); // cy.get('.notification-error'); - cy.wait(10000); + cy.wait(15000); validateColumn( 'article_table_rt', ['title', { name: 'author', columns: ['name'] }], @@ -376,14 +213,10 @@ export const failRTAddSuggestedRel = () => { ); cy.get(getElementFromAlias('article_table_rt')).click(); cy.get(getElementFromAlias('table-relationships')).click(); - cy.get(getElementFromAlias('obj-rel-add-0')) - .last() - .click(); - cy.get('input') - .last() - .type('author'); + cy.get(getElementFromAlias('obj-rel-add-0')).click(); + cy.get(getElementFromAlias('suggested-rel-name')).type('author'); cy.get(getElementFromAlias('obj-rel-save-0')).click(); - cy.wait(10000); + cy.wait(15000); validateColumn( 'article_table_rt', ['title', { name: 'author', columns: ['name'] }], @@ -391,28 +224,13 @@ export const failRTAddSuggestedRel = () => { ); cy.get(getElementFromAlias('article_table_rt')).click(); cy.get(getElementFromAlias('table-relationships')).click(); - cy.get(getElementFromAlias('arr-rel-add-0')) - .contains('Add') - .last() - .click(); - cy.get('input') - .last() - .type('author'); - cy.get('button') - .contains('Save') - .click(); - cy.wait(7000); + cy.get(getElementFromAlias('arr-rel-add-0')).click(); + cy.get(getElementFromAlias('suggested-rel-name')).type('author'); + cy.get(getElementFromAlias('arr-rel-save-0')).click(); + cy.wait(15000); // cy.get('.notification-error'); - cy.wait(7000); - cy.get(getElementFromAlias('article_table_rt')).click(); - cy.get(getElementFromAlias('table-relationships')).click(); - cy.get(getElementFromAlias('remove-button')) - .first() - .click(); - cy.on('window:alert', str => { - expect(str === 'Are you sure?').to.be.true; - }); - cy.wait(7000); + cy.wait(15000); + delRel('article_table_rt', 'author'); }; export const setValidationMetaData = () => { diff --git a/console/cypress/integration/data/relationships/test.js b/console/cypress/integration/data/relationships/test.js index d5771ad1f4e38..c3a3dbfff5718 100644 --- a/console/cypress/integration/data/relationships/test.js +++ b/console/cypress/integration/data/relationships/test.js @@ -11,6 +11,7 @@ import { passRTDeleteRelationships, passRTAddSuggestedRel, failRTAddSuggestedRel, + checkAddManualRelationshipsButton, } from './spec'; import { testMode } from '../../../helpers/common'; import { setMetaData } from '../../validators/validators'; @@ -34,6 +35,10 @@ export const runRelationshipsTests = () => { it('Adding Manual Relationship Object', passRTAddManualObjRel); it('Adding Manual Relationship Array', passRTAddManualArrayRel); it('Adding a Foreign Key', passRTAddForeignKey); + it( + 'Check Add manual relationships button', + checkAddManualRelationshipsButton + ); it('Deleting the relationships', passRTDeleteRelationships); it('Adding Suggested Relationships Error', failRTAddSuggestedRel); it('Adding Suggested Relationships', passRTAddSuggestedRel); diff --git a/console/cypress/integration/data/views/spec.js b/console/cypress/integration/data/views/spec.js index 7f9acc6a31a5b..afbe8f45899b4 100644 --- a/console/cypress/integration/data/views/spec.js +++ b/console/cypress/integration/data/views/spec.js @@ -370,7 +370,7 @@ export const passVAddManualObjRel = () => { cy.wait(2000); cy.get(getElementFromAlias('table-relationships')).click(); cy.wait(2000); - cy.get(getElementFromAlias('data-rel-type')).select('object_rel'); + cy.get(getElementFromAlias('rel-type')).select('object_rel'); cy.get("input[placeholder='Enter relationship name']").type('author'); cy.get('select') .find('option') diff --git a/console/src/components/Services/Data/TableModify/ModifyTable.js b/console/src/components/Services/Data/TableModify/ModifyTable.js index 93aa775fc680e..8af3cd450dede 100644 --- a/console/src/components/Services/Data/TableModify/ModifyTable.js +++ b/console/src/components/Services/Data/TableModify/ModifyTable.js @@ -107,6 +107,7 @@ const ColumnEditor = ({ @@ -149,6 +150,7 @@ const ColumnEditor = ({ disabled={fkAdd.fkCheckBox === false} value={refTable} onChange={onFKRefTableChange} + data-test="ref-table" >