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

Change main stat preprocessing steps add an e2e test #2580

Merged
merged 2 commits into from
Jan 8, 2025

Conversation

legndery
Copy link
Contributor

@legndery legndery commented Dec 17, 2024

Describe your changes

This change aims to replace the bandpass preprocessing steps to a standard blur->dilate->invert->threshold preprocessing for the cropped artifact header.
Additionally, it adds an initial E2E test for testing artifacts.

Original processed header

image

New preprocessed header

image

Issue or discord link

#2368

Testing/validation

Ran few artifact images from my own genshin game.

Running E2e test

Ensure the local dev server is running on http://localhost:4200/
nx serve frontend
Run cypress test
npx nx open-cypress frontend-e2e --config="baseUrl=http://localhost:4200/"
Click on E2E testing + select a browser to open a cypress dashboard in that browser.
Click on src\e2e\app.cy.ts to run the e2e test.
image

Checklist before requesting a review (leave this PR as draft if any part of this list is not done.)

  • I have commented my code in hard-to understand areas.
  • I have made corresponding changes to README or wiki.
  • For front-end changes, I have updated the corresponding English translations.
  • I have run yarn run mini-ci locally to validate format and lint.
  • If I have added a new library or app, I have updated the deployment scripts to ignore changes as needed

Summary by CodeRabbit

  • New Features

    • Introduced a new end-to-end test case for artifact image functionality.
    • Added new image processing capabilities including preprocessing and various filters.
    • Enhanced debug image handling for better tracking during image processing.
  • Improvements

    • Updated the ArtifactEditor component for improved testability and maintainability.
    • Adjusted layout and attributes for better accessibility in the artifact management interface.

Copy link

coderabbitai bot commented Dec 17, 2024

Walkthrough

This pull request introduces enhancements to the artifact image processing and testing infrastructure. The changes span multiple components, including end-to-end testing, image processing utilities, and the artifact editor component. The primary focus is on improving image preprocessing techniques, adding more robust testing for artifact image parsing, and enhancing the testability of the artifact management interface.

Changes

File Change Summary
apps/frontend-e2e/src/e2e/app.cy.ts Added a comprehensive Cypress test case for artifact images, focusing on testing main stat parsing and artifact addition workflow
libs/common/img-util/src/processing.ts Introduced new image processing functions: preprocessImage, thresholdFilter, invertColors, and blurARGB for advanced image manipulation
libs/gi/art-scanner/src/lib/processImg.ts Replaced bandPass with preprocessImage and expanded debug image tracking
libs/gi/ui/src/components/artifact/editor/index.tsx Added data-testid attributes to improve component testability

Sequence Diagram

sequenceDiagram
    participant E2E as Cypress Test
    participant UI as ArtifactEditor
    participant Scanner as ArtifactScanner
    participant ImgUtil as Image Processor

    E2E->>UI: Navigate to Artifacts Page
    E2E->>UI: Close Modal
    E2E->>UI: Add New Artifact
    UI->>Scanner: Upload Image
    Scanner->>ImgUtil: Preprocess Image
    ImgUtil-->>Scanner: Processed Image Data
    Scanner->>UI: Parse Artifact Stats
    E2E->>UI: Verify Main Stat
Loading

Possibly Related PRs

Poem

🐰 In pixels and tests, we dive deep,
Artifacts parsed with a digital leap,
Blurring and scanning, our code takes flight,
Transforming images with algorithmic might!
A rabbit's journey through code so bright 🖼️

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@@ -1,13 +1,35 @@
import { getGreeting } from '../support/app.po'

/* eslint-disable cypress/no-unnecessary-waiting */
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know its better to create a map of some sort from filename to stats and use that. But, its a start, will raise another PR to fix the e2e

Copy link
Contributor

github-actions bot commented Dec 17, 2024

[sr-frontend] [Tue Dec 17 18:00:26 UTC 2024] - Deployed 52316aa to https://genshin-optimizer-prs.github.io/pr/2580/sr-frontend (Takes 3-5 minutes after this completes to be available)

[frontend] [Tue Dec 17 18:00:50 UTC 2024] - Deployed 52316aa to https://genshin-optimizer-prs.github.io/pr/2580/frontend (Takes 3-5 minutes after this completes to be available)

[sr-frontend] [Wed Jan 8 02:15:52 UTC 2025] - Deployed 3c662da to https://genshin-optimizer-prs.github.io/pr/2580/sr-frontend (Takes 3-5 minutes after this completes to be available)

[frontend] [Wed Jan 8 02:16:27 UTC 2025] - Deployed 3c662da to https://genshin-optimizer-prs.github.io/pr/2580/frontend (Takes 3-5 minutes after this completes to be available)

[Wed Jan 8 03:04:41 UTC 2025] - Deleted deployment

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (3)
apps/frontend-e2e/src/e2e/app.cy.ts (1)

1-1: Consider removing the eslint disable comment.

Instead of disabling the cypress/no-unnecessary-waiting rule globally, consider using Cypress's built-in wait mechanisms that are more reliable.

-/* eslint-disable cypress/no-unnecessary-waiting */
libs/common/img-util/src/processing.ts (1)

129-142: Add parameter documentation and consider making parameters configurable.

While the function is documented, the specific values used for blur radius, threshold level, etc., should be documented or made configurable.

 /**
  * This function performs standard image preprocessing. Standard blur,
  * dilate, invert and threshold is done consecutively.
  * @param pixelData imagedata
+ * @param options Configuration object for preprocessing
+ * @param options.blurRadius Radius for Gaussian blur (default: 0.5)
+ * @param options.thresholdLevel Threshold level for binarization (default: 0.4)
  * @returns a preprocessed cloned image
  */
-export function preprocessImage(pixelData: ImageData) {
+export function preprocessImage(
+  pixelData: ImageData,
+  options = { blurRadius: 0.5, thresholdLevel: 0.4 }
+) {
   const imageClone = Uint8ClampedArray.from(pixelData.data)
-  blurARGB(imageClone, pixelData.width, pixelData.height, 0.5)
+  blurARGB(imageClone, pixelData.width, pixelData.height, options.blurRadius)
   dilate(imageClone, pixelData.width)
   invertColors(imageClone)
-  thresholdFilter(imageClone, 0.4)
+  thresholdFilter(imageClone, options.thresholdLevel)
   return new ImageData(imageClone, pixelData.width, pixelData.height)
 }
libs/gi/ui/src/components/artifact/editor/index.tsx (1)

554-559: Consider enhancing test ID coverage for child elements.

While adding data-testid="main-stat" to the Box component is good, consider also adding test IDs to the interactive elements within this section (e.g., DropdownButton, MenuItem) to facilitate more granular e2e testing scenarios.

Example additions:

 <DropdownButton
+  data-testid="main-stat-dropdown"
   startIcon={
     artifact?.mainStatKey ? (
       <StatIcon statKey={artifact.mainStatKey} />
     ) : undefined
   }
   // ... rest of the code
 >
   {artSlotMainKeys[slotKey].map((mainStatK) => (
     <MenuItem
+      data-testid={`main-stat-option-${mainStatK}`}
       key={mainStatK}
       // ... rest of the code
     >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66413c0 and c3b21df.

⛔ Files ignored due to path filters (2)
  • apps/frontend-e2e/assets/def_p_8_7.png is excluded by !**/*.png
  • apps/frontend-e2e/assets/em_155.png is excluded by !**/*.png
📒 Files selected for processing (4)
  • apps/frontend-e2e/src/e2e/app.cy.ts (1 hunks)
  • libs/common/img-util/src/processing.ts (1 hunks)
  • libs/gi/art-scanner/src/lib/processImg.ts (2 hunks)
  • libs/gi/ui/src/components/artifact/editor/index.tsx (2 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
libs/common/img-util/src/processing.ts

[error] 204-204: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

🔇 Additional comments (3)
libs/gi/art-scanner/src/lib/processImg.ts (1)

243-243: Verify the impact of preprocessing changes.

The switch from bandPass to preprocessImage for header processing is a significant change. Ensure this change maintains or improves the accuracy of text extraction.

✅ Verification successful

The preprocessing change is an improvement in image processing

The switch from bandPass to preprocessImage for header processing is actually a more robust approach. The preprocessImage function applies a series of image processing operations including:

  1. Gaussian blur for noise reduction
  2. Dilation to enhance text features
  3. Color inversion
  4. Threshold filtering for binary image output

This combination is specifically designed for text extraction, making it more suitable for header processing than the simpler bandPass function.

Key observations:

  • bandPass is still used for other parts of the image where color-based filtering is needed
  • The preprocessing pipeline follows established computer vision practices for text extraction
  • The implementation is based on well-tested image processing algorithms from p5.js
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any related test files or image processing configurations
# that might need updates due to the preprocessing change.

# Look for test files related to image processing
fd -e test.ts -e spec.ts . | xargs rg -l "bandPass|preprocessImage"

# Look for configuration files that might contain image processing parameters
fd -e config.ts -e json . | xargs rg -l "bandPass|preprocessImage"

Length of output: 138


Script:

#!/bin/bash
# Let's try a broader search to understand the usage and testing of these image processing functions

# Search for bandPass and preprocessImage function definitions and usages
rg -l "function\s+(bandPass|preprocessImage)" --type ts

# Search for test files containing any image processing related terms
rg -l "test|describe|it.*(\bimage\b|\bpreprocess\b|\bheader\b|\btext extraction\b)" --type ts

# Look for any image processing related configuration or constants
rg -l "(\bimage\b|\bpreprocess\b|\bheader\b)\s*(:|=)\s*{" --type ts

Length of output: 5378


Script:

#!/bin/bash
# Let's examine the image processing functions in the identified files

# Check the implementation of preprocessImage and bandPass
rg -A 10 "function\s+(preprocessImage|bandPass)" libs/common/img-util/src/processing.ts

# Look for tests specifically related to image preprocessing
rg -A 10 "(test|describe|it).*(\bpreprocess|\bimage)" libs/common/img-util/src/processing.ts

# Check for any usage of these functions in the art-scanner module
rg "(preprocessImage|bandPass)" libs/gi/art-scanner/src/

Length of output: 2990

libs/gi/ui/src/components/artifact/editor/index.tsx (2)

431-431: LGTM! Test ID added for modal wrapper.

The addition of data-testid="artifact-editor" aligns with the PR's objective of adding e2e tests.


Line range hint 431-559: Verify test ID usage in e2e tests.

Let's verify that these newly added test IDs are being utilized in the e2e tests mentioned in the PR objectives.

✅ Verification successful

Test IDs are properly utilized in e2e tests

The test IDs artifact-editor and main-stat are actively being used in the e2e test file apps/frontend-e2e/src/e2e/app.cy.ts for verifying artifact editor functionality, including main stat value and text assertions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of the new test IDs in e2e test files
echo "Searching for test ID usage in e2e tests..."
rg -l "artifact-editor|main-stat" "apps/frontend-e2e/src/e2e"

Length of output: 194


Script:

#!/bin/bash
# Let's check the actual usage context of these test IDs in the e2e test file
rg -A 5 -B 5 "artifact-editor|main-stat" "apps/frontend-e2e/src/e2e/app.cy.ts"

Length of output: 865

Comment on lines +20 to +33
cy.contains('button', 'Clear').click()
cy.wait(500)

// Function helper example, see `../support/app.po.ts` file
getGreeting().contains('Welcome frontend')
cy.contains('label', 'Upload Screenshot').selectFile('assets/def_p_8_7.png')
cy.wait(5000)
cy.contains('button', 'Add Artifact', { timeout: 60000 }).should(
'not.be.disabled'
)
cy.get(
'[data-testid="artifact-editor"] [data-testid="main-stat"] button'
).should('have.text', 'DEF%')
cy.get(
'[data-testid="artifact-editor"] [data-testid="main-stat"] p'
).should('have.text', '8.7%')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Extract repeated test logic into a custom command.

The second image test repeats the same steps as the first one. Consider creating a custom Cypress command to reduce duplication.

// In commands.ts
Cypress.Commands.add('verifyArtifactMainStat', (imagePath: string, expectedStat: string, expectedValue: string) => {
  cy.contains('button', 'Clear').click()
  cy.contains('label', 'Upload Screenshot').selectFile(imagePath)
  cy.get('[data-testid="artifact-editor"]').should('exist')
  cy.get('button').contains('Add Artifact').should('not.be.disabled')
  cy.get('[data-testid="artifact-editor"] [data-testid="main-stat"] button').should('have.text', expectedStat)
  cy.get('[data-testid="artifact-editor"] [data-testid="main-stat"] p').should('have.text', expectedValue)
})

// In test
it('should correctly parse main stats from artifact screenshots', () => {
  cy.visit('/#/artifacts')
  cy.get('.MuiModal-root [data-testid="CloseIcon"]').click()
  cy.verifyArtifactMainStat('assets/em_155.png', 'Elemental Mastery', '155')
  cy.verifyArtifactMainStat('assets/def_p_8_7.png', 'DEF%', '8.7%')
})

Comment on lines +3 to +5
it('should test artifacts images to check if main stat is being parsed correctly', () => {
cy.visit('/#/artifacts', { timeout: 600000 })
cy.get('.MuiModal-root [data-testid="CloseIcon"]').click()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add test description and improve timeout handling.

The test description could be more specific, and the timeout should be moved to Cypress configuration.

-  it('should test artifacts images to check if main stat is being parsed correctly', () => {
-    cy.visit('/#/artifacts', { timeout: 600000 })
+  it('should correctly parse main stats from artifact screenshots', () => {
+    cy.visit('/#/artifacts')

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +8 to +18
cy.contains('label', 'Upload Screenshot').selectFile('assets/em_155.png')
cy.wait(5000)
cy.contains('button', 'Add Artifact', { timeout: 60000 }).should(
'not.be.disabled'
)
cy.get(
'[data-testid="artifact-editor"] [data-testid="main-stat"] button'
).should('have.text', 'Elemental Mastery')
cy.get(
'[data-testid="artifact-editor"] [data-testid="main-stat"] p'
).should('have.text', '155')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace fixed waits with proper assertions.

Using fixed wait times can make tests flaky. Instead, use Cypress's built-in retry-ability and assertions.

-    cy.wait(5000)
+    cy.get('[data-testid="artifact-editor"]').should('exist')
+    cy.get('@addArtifact').should('not.be.disabled')

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +173 to +211
// internal kernel stuff for the gaussian blur filter
let blurRadius: number
let blurKernelSize: number
let blurKernel: Int32Array
let blurMult: Array<Int32Array>

// from https://github.com/processing/p5.js/blob/main/src/image/filters.js
function buildBlurKernel(r: number) {
let radius = (r * 3.5) | 0
radius = radius < 1 ? 1 : radius < 248 ? radius : 248

if (blurRadius !== radius) {
blurRadius = radius
blurKernelSize = (1 + blurRadius) << 1
blurKernel = new Int32Array(blurKernelSize)
blurMult = new Array(blurKernelSize)
for (let l = 0; l < blurKernelSize; l++) {
blurMult[l] = new Int32Array(256)
}

let bki: number
let bm, bmi: Int32Array

for (let i = 1, radiusi = radius - 1; i < radius; i++) {
blurKernel[radius + i] = blurKernel[radiusi] = bki = radiusi * radiusi
bm = blurMult[radius + i]
bmi = blurMult[radiusi--]
for (let j = 0; j < 256; j++) {
bm[j] = bmi[j] = bki * j
}
}
const bk = (blurKernel[radius] = radius * radius)
bm = blurMult[radius]

for (let k = 0; k < 256; k++) {
bm[k] = bk * k
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider encapsulating blur kernel state.

The blur kernel implementation uses global variables which could lead to issues in concurrent processing. Consider encapsulating this state within a class.

class GaussianBlur {
  private blurRadius: number;
  private blurKernelSize: number;
  private blurKernel: Int32Array;
  private blurMult: Array<Int32Array>;

  constructor() {
    this.blurRadius = 0;
    this.blurKernelSize = 0;
    this.blurKernel = new Int32Array(0);
    this.blurMult = [];
  }

  buildKernel(r: number) {
    // ... existing buildBlurKernel logic ...
  }

  blur(pixels: Uint8ClampedArray, width: number, height: number, radius: number) {
    // ... existing blurARGB logic using class properties ...
  }
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 204-204: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

bm[j] = bmi[j] = bki * j
}
}
const bk = (blurKernel[radius] = radius * radius)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix assignment in expression.

The static analysis tool correctly flags an assignment within an expression. This should be split into separate statements for better readability.

-    const bk = (blurKernel[radius] = radius * radius)
+    const bk = radius * radius
+    blurKernel[radius] = bk
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const bk = (blurKernel[radius] = radius * radius)
const bk = radius * radius
blurKernel[radius] = bk
🧰 Tools
🪛 Biome (1.9.4)

[error] 204-204: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

Copy link
Owner

@frzyc frzyc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I've also ran e2e tests locally, and updated the PR description with updated steps and preprocessed image.

@frzyc frzyc merged commit 451d0e2 into frzyc:master Jan 8, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants