Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting up Karate Test for GraphQl #42

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,7 @@ bower_components/
# Test output
test-output/
*.tap

# Karate reports
tests/target/
tests/results/
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"express-rate-limit": "^7.4.1",
"graphql-request": "^7.1.2",
"nodemailer": "^6.9.16",
"winston": "^3.17.0"
"winston": "^3.17.0",
"cucumber-html-reporter": "^5.5.0",
"karate-core": "^1.4.0"
}
}
15 changes: 15 additions & 0 deletions tests/Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM maven:3.8-openjdk-17

WORKDIR /app

# Copy the POM file
COPY pom.xml .

# Copy the test files
COPY . .

# Create directory for reports
RUN mkdir -p target/karate-reports

# Wait for GraphQL engine to be ready and then run tests
CMD ["sh", "-c", "sleep 10 && mvn test"]
65 changes: 65 additions & 0 deletions tests/docker-compose.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
services:
postgres:
olisaagbafor marked this conversation as resolved.
Show resolved Hide resolved
olisaagbafor marked this conversation as resolved.
Show resolved Hide resolved
image: postgis/postgis:15-3.3
environment:
POSTGRES_PASSWORD: postgrespassword
POSTGRES_DB: safetrust
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d safetrust"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
- safetrust-network
volumes:
- postgres_data:/var/lib/postgresql/data
command: ["postgres", "-c", "logging_collector=on", "-c", "log_statement=all"]

graphql-engine:
olisaagbafor marked this conversation as resolved.
Show resolved Hide resolved
image: hasura/graphql-engine:v2.33.4
ports:
- "8080:8080"
depends_on:
postgres:
condition: service_healthy
environment:
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/safetrust
HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
HASURA_GRAPHQL_DEV_MODE: "true"
HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey
HASURA_GRAPHQL_JWT_SECRET: '{"type":"RS256","jwk_url": "https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com","audience": "safetrust-dev", "issuer": "https://securetoken.google.com/safetrust-dev"}'
restart: always
networks:
- safetrust-network

karate:
build:
context: .
dockerfile: Dockerfile.test
volumes:
- ./:/app
- ./results:/app/target/karate-reports
environment:
HASURA_ENDPOINT: http://graphql-engine:8080/v1/graphql
HASURA_ADMIN_SECRET: myadminsecretkey
FIREBASE_PROJECT_ID: safetrust-dev
depends_on:
postgres:
condition: service_healthy
graphql-engine:
condition: service_started
networks:
- safetrust-network
tty: true
stdin_open: true

networks:
safetrust-network:
driver: bridge

volumes:
postgres_data:
20 changes: 20 additions & 0 deletions tests/karate-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function fn() {
karate.configure("logPrettyRequest", true);
karate.configure("logPrettyResponse", true);

const config = {
baseUrl: "http://graphql-engine:8080/v1/graphql",
adminSecret: "myadminsecretkey",
};

// Reference the JWT secret from docker-compose.yml
const jwtConfig = {
type: "RS256",
audience: "safetrust-dev",
issuer: "https://securetoken.google.com/safetrust-dev",
};

config.authHeader = "Bearer " + karate.callSingle("classpath:helpers/generate-token.js", jwtConfig);

return config;
}
41 changes: 41 additions & 0 deletions tests/karate/features/auth/login.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Feature: Authentication Tests

Background:
* url baseUrl
* def tokenHelper = read('classpath:helpers/generate-token.js')

Scenario: Valid Firebase Token Authentication
* def validToken = tokenHelper({ uid: 'test-user', role: 'user' })
Given path '/v1/graphql'
And header Authorization = 'Bearer ' + validToken
And request {
query: """
query { users { id } }
"""
}
When method POST
Then status 200
And match response.errors == '#notpresent'

Scenario: Expired Token Authentication
* def expiredToken = tokenHelper({ uid: 'test-user', exp: '#(~~(Date.now()/1000 - 3600))' })
Given path '/v1/graphql'
And header Authorization = 'Bearer ' + expiredToken
And request {
query: """
query { users { id } }
"""
}
When method POST
Then status 401

Scenario: Invalid Token Format
Given path '/v1/graphql'
And header Authorization = 'Bearer invalid.token.format'
And request {
query: """
query { users { id } }
"""
}
When method POST
Then status 401
27 changes: 27 additions & 0 deletions tests/karate/features/auth/permissions.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Feature: User Permissions

Background:
* url baseUrl
* def testUserId = 'test-user-id'

Scenario: Verify User Role Permissions
Given path '/v1/graphql'
And header Authorization = authHeader
And header x-hasura-role = 'users'
And request {
query: """
query GetUserProfile($userId: String!) {
users_by_pk(id: $userId) {
id
email
first_name
last_name
}
}
""",
variables: { userId: testUserId }
}
When method POST
Then status 200
And match response.data.users_by_pk != null
And match response.errors == '#notpresent'
55 changes: 55 additions & 0 deletions tests/karate/features/users/create.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
Feature: User Creation

Background:
* url baseUrl
* def adminSecret = karate.get('adminSecret')
* header x-hasura-admin-secret = adminSecret

Scenario: Create New User
Given path '/v1/graphql'
And request {
query: """
mutation CreateUser($user: users_insert_input!) {
insert_users_one(object: $user) {
id
email
first_name
last_name
}
}
""",
variables: {
user: {
id: 'test-user-' + Date.now(),
email: 'test@example.com',
first_name: 'Test',
last_name: 'User'
}
}
}
When method POST
Then status 200
And match response.data.insert_users_one != null
And match response.errors == '#notpresent'

Scenario: Prevent Duplicate Email
Given path '/v1/graphql'
And request {
query: """
mutation CreateUser($user: users_insert_input!) {
insert_users_one(object: $user) {
id
email
}
}
""",
variables: {
user: {
id: 'test-user-' + Date.now(),
email: 'existing@example.com'
}
}
}
When method POST
Then status 200
And match response.errors[0].message contains 'unique constraint'
48 changes: 48 additions & 0 deletions tests/karate/features/users/query.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Feature: User Queries

Background:
* url baseUrl
* header x-hasura-admin-secret = adminSecret

Scenario: Query User Profile
Given path '/v1/graphql'
And request {
query: """
query GetUserProfile($userId: String!) {
users_by_pk(id: $userId) {
id
email
first_name
last_name
country_code
phone_number
last_seen
}
}
""",
variables: { userId: 'test-user-id' }
}
When method POST
Then status 200
And match response.data.users_by_pk != null
And match response.errors == '#notpresent'

Scenario: Query User Wallets
Given path '/v1/graphql'
And request {
query: """
query GetUserWallets($userId: String!) {
user_wallets(where: {user_id: {_eq: $userId}}) {
id
wallet_address
chain_type
is_primary
}
}
""",
variables: { userId: 'test-user-id' }
}
When method POST
Then status 200
And match response.data.user_wallets == '#array'
And match response.errors == '#notpresent'
56 changes: 56 additions & 0 deletions tests/karate/features/users/wallets.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Feature: User Wallets

Background:
* url baseUrl
* def userId = 'test-user-id'
* def adminSecret = karate.get('adminSecret')
* header x-hasura-admin-secret = adminSecret

Scenario: Create Primary Wallet
Given path '/v1/graphql'
And request {
query: """
mutation CreateWallet($wallet: user_wallets_insert_input!) {
insert_user_wallets_one(object: $wallet) {
id
wallet_address
is_primary
chain_type
}
}
""",
variables: {
wallet: {
user_id: '#(userId)',
wallet_address: '0x' + Date.now(),
chain_type: 'ETH',
is_primary: true
}
}
}
When method POST
Then status 200
And match response.data.insert_user_wallets_one.is_primary == true

Scenario: Validate Wallet Address Format
Given path '/v1/graphql'
And request {
query: """
mutation CreateWallet($wallet: user_wallets_insert_input!) {
insert_user_wallets_one(object: $wallet) {
id
wallet_address
}
}
""",
variables: {
wallet: {
user_id: '#(userId)',
wallet_address: 'invalid-address',
chain_type: 'ETH'
}
}
}
When method POST
Then status 200
And match response.errors[0].message contains 'check_valid_wallet_address'
29 changes: 29 additions & 0 deletions tests/karate/helpers/schemas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
function fn() {
const schemas = {
user: {
id: "#string",
email: "#string",
first_name: "##string",
last_name: "##string",
country_code: "##string",
phone_number: "##string",
last_seen: "#string",
},
wallet: {
id: "#string",
wallet_address: "#string",
chain_type: "#string",
is_primary: "#boolean",
created_at: "#string",
},
error: {
message: "#string",
extensions: {
code: "#string",
path: "#array",
},
},
};

return schemas;
}
Loading