Skip to content

Commit

Permalink
Merge pull request #226 from RedisInsight/feature/stories
Browse files Browse the repository at this point in the history
#RIVS-303, #RIVS-304, #RIVS-313, #RIVS-314, #RIVS-305
  • Loading branch information
vlad-dargel authored Dec 17, 2024
2 parents b86d53f + 1a1f928 commit 31c9472
Show file tree
Hide file tree
Showing 34 changed files with 708 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ RI_STDOUT_LOGGER=false
RI_AUTO_BOOTSTRAP=false
RI_MIGRATE_OLD_FOLDERS=false
RI_BUILD_TYPE='VS_CODE'
RI_ENCRYPTION_KEYTAR=false
RI_ANALYTICS_START_EVENTS=true
RI_AGREEMENTS_PATH='../../webviews/resources/agreements-spec.json'
RI_ENCRYPTION_KEYTAR_SERVICE="redis-for-vscode"
# RI_SEGMENT_WRITE_KEY='SEGMENT_WRITE_KEY'
4 changes: 2 additions & 2 deletions .github/workflows/pipeline-build-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
uses: ./.github/actions/download-backend

- name: Set RI_SEGMENT_WRITE_KEY to .env file
run: echo "RI_SEGMENT_WRITE_KEY='$RI_SEGMENT_WRITE_KEY'" >> $envFile
run: echo "RI_SEGMENT_WRITE_KEY='${{ env.RI_SEGMENT_WRITE_KEY }}'" >> ${{ env.envFile }}

- name: Build linux package (production)
if: inputs.environment == 'production'
Expand All @@ -45,7 +45,7 @@ jobs:
- name: Build linux package (staging)
if: inputs.environment == 'staging'
run: |
sed -i "s/^RI_APP_FOLDER_NAME=.*/RI_APP_FOLDER_NAME='.redis-for-vscode-stage'/" $envFile
sed -i "s/^RI_APP_FOLDER_NAME=.*/RI_APP_FOLDER_NAME='.redis-for-vscode-stage'/" ${{ env.envFile }}
yarn package:stage --target linux-x64 --out ${packagePath}
- uses: actions/upload-artifact@v4
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pipeline-build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
uses: ./.github/actions/install-all-build-libs

- name: Set RI_SEGMENT_WRITE_KEY to .env file
run: echo "RI_SEGMENT_WRITE_KEY='$RI_SEGMENT_WRITE_KEY'" >> $envFile
run: echo "RI_SEGMENT_WRITE_KEY='${{ env.RI_SEGMENT_WRITE_KEY }}'" >> ${{ env.envFile }}

- name: Download backend x64
uses: ./.github/actions/download-backend
Expand All @@ -38,7 +38,7 @@ jobs:
- name: Build macos x64 package (staging)
if: inputs.environment != 'production'
run: |
sed -i '' "s/^RI_APP_FOLDER_NAME=.*/RI_APP_FOLDER_NAME='.redis-for-vscode-stage'/" $envFile
sed -i '' "s/^RI_APP_FOLDER_NAME=.*/RI_APP_FOLDER_NAME='.redis-for-vscode-stage'/" ${{ env.envFile }}
yarn package:stage --target darwin-x64 --out ${packagePath}-x64.vsix
Expand All @@ -55,7 +55,7 @@ jobs:
- name: Build macos arm64 package (staging)
if: inputs.environment != 'production'
run: |
sed -i '' "s/^RI_APP_FOLDER_NAME=.*/RI_APP_FOLDER_NAME='.redis-for-vscode-stage'/" $envFile
sed -i '' "s/^RI_APP_FOLDER_NAME=.*/RI_APP_FOLDER_NAME='.redis-for-vscode-stage'/" ${{ env.envFile }}
yarn package:stage --target darwin-arm64 --out ${packagePath}-arm64.vsix
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pipeline-build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
uses: ./.github/actions/download-backend

- name: Set RI_SEGMENT_WRITE_KEY to .env file
run: echo "RI_SEGMENT_WRITE_KEY='$RI_SEGMENT_WRITE_KEY'" >> $envFile
run: echo "RI_SEGMENT_WRITE_KEY='${{ env.RI_SEGMENT_WRITE_KEY }}'" >> ${{ env.envFile }}

- name: Build windows package (production)
if: inputs.environment == 'production'
Expand All @@ -35,7 +35,7 @@ jobs:
- name: Build windows package (staging)
if: inputs.environment == 'staging'
run: |
sed -i "s/^RI_APP_FOLDER_NAME=.*/RI_APP_FOLDER_NAME='.redis-for-vscode-stage'/" $envFile
sed -i "s/^RI_APP_FOLDER_NAME=.*/RI_APP_FOLDER_NAME='.redis-for-vscode-stage'/" ${{ env.envFile }}
yarn package:stage --target win32-x64 --out ${{ env.packagePath }}
- uses: actions/upload-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests-e2e-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20.15'
node-version: '20.18.0'

- name: Download linux artifact
uses: actions/download-artifact@v4
Expand Down
47 changes: 32 additions & 15 deletions .github/workflows/tests-frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@ on:
workflow_call:

env:
SLACK_AUDIT_REPORT_CHANNEL: ${{ secrets.SLACK_AUDIT_REPORT_CHANNEL }}
SLACK_AUDIT_REPORT_KEY: ${{ secrets.SLACK_AUDIT_REPORT_KEY }}
AWS_BUCKET_NAME_TEST: ${{ vars.AWS_BUCKET_NAME_TEST }}
AWS_DEFAULT_REGION: ${{ vars.AWS_DEFAULT_REGION }}
AWS_DISTRIBUTION_ID: ${{ secrets.AWS_DISTRIBUTION_ID }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
REPORT_NAME: "report-vscode-fe"
S3_PATH: "report-vscode-fe"

jobs:
unit-tests:
Expand All @@ -18,21 +26,30 @@ jobs:
- name: Unit tests UI
run: yarn test:cov

- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
- name: Get current date
id: date
if: always()
with:
check_name: 'FE Unit tests summary'
comment_mode: 'failures'
files: reports/junit.xml
uses: RedisInsight/RedisInsight/.github/actions/get-current-date@873a0ebf55c85d3127bb4efb4d0636d9ab838226

- name: Generate test results
uses: dorny/test-reporter@v1

- name: Deploy 🚀
if: always()
run: |
GZIP_FILE=html.meta.json.gz
S3_SUB_PATH="test-reports/${{ steps.date.outputs.date }}/${{ github.run_id }}/${{ env.REPORT_NAME }}"
aws s3 cp report/ s3://${AWS_BUCKET_NAME_TEST}/public/${S3_SUB_PATH} --recursive --exclude "*.gz"
# s3 modified "gzip" content-type
# https://github.com/aws/aws-cli/issues/1131
aws s3 cp report/${GZIP_FILE} s3://${AWS_BUCKET_NAME_TEST}/public/${S3_SUB_PATH}/${GZIP_FILE} --content-type "application/x-gzip" --metadata-directive REPLACE
echo "S3_SUB_PATH=${S3_SUB_PATH}" >> $GITHUB_ENV
- name: Add link to report in the workflow summary
if: always()
with:
name: 'Test results: FE unit tests'
path: reports/junit.xml
reporter: jest-junit
list-tests: 'failed'
list-suites: 'failed'
fail-on-error: 'false'
run: |
link="${{ vars.DEFAULT_TEST_REPORTS_URL }}/${S3_SUB_PATH}/index.html"
echo "[${link}](${link})" >> $GITHUB_STEP_SUMMARY
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.4.5",
"upath": "^2.0.1",
"uuid": "^9.0.1",
"vite": "^5.2.10",
"vite-plugin-react-click-to-component": "^3.0.0",
Expand Down
19 changes: 18 additions & 1 deletion scripts/downloadBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import * as fs from 'fs'
import * as path from 'path'
import * as cp from 'child_process'
import * as dotenv from 'dotenv'
import * as upath from 'upath'
import { parse as parseUrl } from 'url'


dotenv.config({
path: [
path.join(__dirname, '..', '.env'),
Expand Down Expand Up @@ -80,13 +82,28 @@ async function downloadRedisBackendArchive(
})
}

function getNormalizedString(string: string) {
return string?.startsWith('D:')
? upath.normalize(string).replace('D:', '/d')
: string
}

function unzipRedisServer(redisInsideArchivePath: string, extractDir: string) {
// tar does not create extractDir by default
if (!fs.existsSync(extractDir)) {
fs.mkdirSync(extractDir)
}

cp.spawnSync('tar', ['-xf', redisInsideArchivePath, '-C', extractDir, '--strip-components', '1', 'api'])
cp.spawnSync('tar', [
'-xf',
getNormalizedString(redisInsideArchivePath),
'-C',
getNormalizedString(extractDir),
'--strip-components',
'1',
'api',
])


// remove tutorials
fs.rmSync(tutorialsPath, { recursive: true, force: true });
Expand Down
33 changes: 32 additions & 1 deletion src/resources/agreements-spec.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.0.1",
"version": "1.0.2",
"agreements": {
"analytics": {
"defaultValue": false,
Expand Down Expand Up @@ -35,6 +35,37 @@
"title": "Server Side Public License",
"label": "I have read and understood the Terms",
"requiredText": "Accept the Server Side Public License"
},
"encryption": {
"conditional": true,
"checker": "KEYTAR",
"defaultOption": "false",
"options": {
"true": {
"defaultValue": true,
"displayInSetting": false,
"required": false,
"editable": true,
"disabled": false,
"category": "privacy",
"since": "1.0.2",
"title": "Encryption",
"label": "Encrypt sensitive information",
"description": "Select to encrypt sensitive information using system keychain. Otherwise, this information is stored locally in plain text, which may incur security risk."
},
"false": {
"defaultValue": false,
"displayInSetting": false,
"required": false,
"editable": true,
"disabled": true,
"category": "privacy",
"since": "1.0.2",
"title": "Encryption",
"label": "Encrypt sensitive information",
"description": "Install or enable the system keychain to encrypt and securely store your sensitive information added before using the application. Otherwise, this information will be stored locally in plain text and may lead to security risks."
}
}
}
}
}
158 changes: 158 additions & 0 deletions src/webviews/src/components/auto-refresh/AutoRefresh.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import React from 'react'
import { instance, mock } from 'ts-mockito'
import { fireEvent, screen, render, act } from 'testSrc/helpers'
import { AutoRefresh, Props } from './AutoRefresh'
import { DEFAULT_REFRESH_RATE } from './utils'

const mockedProps = mock<Props>()

const INLINE_ITEM_EDITOR = 'inline-item-editor'

describe('AutoRefresh', () => {
it('should render', () => {
expect(render(<AutoRefresh {...instance(mockedProps)} />)).toBeTruthy()
})

it('prop "displayText = true" should show Refresh text', () => {
const { queryByTestId } = render(<AutoRefresh {...instance(mockedProps)} displayText />)

expect(queryByTestId('refresh-message-label')).toBeInTheDocument()
})

it('prop "displayText = false" should hide Refresh text', () => {
const { queryByTestId } = render(<AutoRefresh {...instance(mockedProps)} displayText={false} />)

expect(queryByTestId('refresh-message-label')).not.toBeInTheDocument()
})

it('should call onRefresh', () => {
const onRefresh = vi.fn()
render(<AutoRefresh {...instance(mockedProps)} onRefresh={onRefresh} />)

fireEvent.click(screen.getByTestId('refresh-btn'))
expect(onRefresh).toBeCalled()
})

it('refresh text should contain "Last refresh" time with disabled auto-refresh', async () => {
render(<AutoRefresh {...instance(mockedProps)} displayText />)

expect(screen.getByTestId('refresh-message-label')).toHaveTextContent(/Last refresh:/i)
expect(screen.getByTestId('refresh-message')).toHaveTextContent('now')
})

it('refresh text should contain "Auto-refresh" time with enabled auto-refresh', async () => {
render(<AutoRefresh {...instance(mockedProps)} displayText />)

fireEvent.click(screen.getByTestId('auto-refresh-config-btn'))
fireEvent.click(screen.getByTestId('auto-refresh-switch'))

expect(screen.getByTestId('refresh-message-label')).toHaveTextContent(/Auto refresh:/i)
expect(screen.getByTestId('refresh-message')).toHaveTextContent(DEFAULT_REFRESH_RATE)
})

it('should locate refresh message label when testid is provided', () => {
render(<AutoRefresh {...instance(mockedProps)} displayText testid="testid" />)

expect(screen.getByTestId('testid-refresh-message-label')).toBeInTheDocument()
})

it('should locate refresh message when testid is provided', () => {
render(<AutoRefresh {...instance(mockedProps)} displayText testid="testid" />)

expect(screen.getByTestId('testid-refresh-message')).toBeInTheDocument()
})

it('should locate refresh button when testid is provided', () => {
render(<AutoRefresh {...instance(mockedProps)} testid="testid" />)

expect(screen.getByTestId('testid-refresh-btn')).toBeInTheDocument()
})

it('should locate auto-refresh config button when testid is provided', () => {
render(<AutoRefresh {...instance(mockedProps)} testid="testid" />)

expect(screen.getByTestId('testid-auto-refresh-config-btn')).toBeInTheDocument()
})

it('should locate auto-refresh switch when testid is provided', () => {
render(<AutoRefresh {...instance(mockedProps)} testid="testid" />)

fireEvent.click(screen.getByTestId('testid-auto-refresh-config-btn'))
expect(screen.getByTestId('testid-auto-refresh-switch')).toBeInTheDocument()
})

describe('AutoRefresh Config', () => {
it('Auto refresh config should render', () => {
const { queryByTestId } = render(<AutoRefresh {...instance(mockedProps)} />)

fireEvent.click(screen.getByTestId('auto-refresh-config-btn'))
expect(queryByTestId('auto-refresh-switch')).toBeInTheDocument()
})

it('should call onRefresh after enable auto-refresh and set 1 sec', async () => {
const onRefresh = vi.fn()
render(<AutoRefresh {...instance(mockedProps)} onRefresh={onRefresh} />)

fireEvent.click(screen.getByTestId('auto-refresh-config-btn'))
fireEvent.click(screen.getByTestId('auto-refresh-switch'))
fireEvent.click(screen.getByTestId(INLINE_ITEM_EDITOR))

fireEvent.input(screen.getByTestId(INLINE_ITEM_EDITOR), { target: { value: '1' } })
expect(screen.getByTestId(INLINE_ITEM_EDITOR)).toHaveValue('1')

screen.getByTestId(/apply-btn/).click()

await act(async () => {
await new Promise((r) => setTimeout(r, 1300))
})
expect(onRefresh).toBeCalledTimes(1)

await act(async () => {
await new Promise((r) => setTimeout(r, 1300))
})
expect(onRefresh).toBeCalledTimes(2)

await act(async () => {
await new Promise((r) => setTimeout(r, 1300))
})
expect(onRefresh).toBeCalledTimes(3)
})
})

it('should NOT call onRefresh with disabled state', async () => {
const onRefresh = vi.fn()
const { rerender } = render(<AutoRefresh {...instance(mockedProps)} onRefresh={onRefresh} />)

fireEvent.click(screen.getByTestId('auto-refresh-config-btn'))
fireEvent.click(screen.getByTestId('auto-refresh-switch'))
fireEvent.click(screen.getByTestId(INLINE_ITEM_EDITOR))
fireEvent.input(screen.getByTestId(INLINE_ITEM_EDITOR), { target: { value: '1' } })

expect(screen.getByTestId(INLINE_ITEM_EDITOR)).toHaveValue('1')

screen.getByTestId(/apply-btn/).click()

await act(() => {
rerender(<AutoRefresh {...instance(mockedProps)} onRefresh={onRefresh} disabled />)
})

await act(async () => {
await new Promise((r) => setTimeout(r, 1300))
})
expect(onRefresh).toBeCalledTimes(0)

await act(async () => {
await new Promise((r) => setTimeout(r, 1300))
})
expect(onRefresh).toBeCalledTimes(0)

await act(() => {
rerender(<AutoRefresh {...instance(mockedProps)} onRefresh={onRefresh} disabled={false} />)
})

await act(async () => {
await new Promise((r) => setTimeout(r, 1300))
})
expect(onRefresh).toBeCalledTimes(1)
})
})
Loading

0 comments on commit 31c9472

Please sign in to comment.