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

#RIVS-303, #RIVS-304, #RIVS-313, #RIVS-314, #RIVS-305 #226

Merged
merged 7 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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
Loading