Skip to content

Commit

Permalink
Merge pull request #2 from vertexcover-io/feat/tests
Browse files Browse the repository at this point in the history
Add tests and github actions
  • Loading branch information
Neeraj319 authored Oct 24, 2024
2 parents 9d5bd73 + b2aebc5 commit 10bc856
Show file tree
Hide file tree
Showing 13 changed files with 518 additions and 96 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Run-tests
on:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
contents: read
jobs:
unit:
strategy:
matrix:
go: ['1.23.2']
os: [ubuntu-latest, macos-latest, windows-latest]
fail-fast: true
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Code
uses: actions/checkout@v3

- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
cache: false

- name: Run Tests
run: go test -race -cover -coverprofile=coverage -covermode=atomic -v ./...
2 changes: 1 addition & 1 deletion locatr/elementSpec.go → core/elementSpec.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package locatr
package core

import (
"fmt"
Expand Down
83 changes: 83 additions & 0 deletions core/element_spec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package core

import (
"testing"
)

func TestContentStr(t *testing.T) {
tests := []struct {
name string
element ElementSpec
expected string
}{
{
name: "Single element with no attributes or children",
element: ElementSpec{
ID: "1",
TagName: "div",
Text: "Hello World",
},
expected: `<div id="1">Hello World</div>`,
},
{
name: "Element with attributes",
element: ElementSpec{
ID: "2",
TagName: "span",
Text: "Hello",
Attributes: map[string]string{
"class": "greeting",
"style": "color: red;",
},
},
expected: `<span class="greeting" style="color: red;" id="2">Hello</span>`,
},
{
name: "Element with children",
element: ElementSpec{
ID: "3",
TagName: "ul",
Children: []ElementSpec{
{
ID: "4",
TagName: "li",
Text: "Item 1",
},
{
ID: "5",
TagName: "li",
Text: "Item 2",
},
},
},
expected: `<ul id="3"><li id="4">Item 1</li><li id="5">Item 2</li></ul>`,
},
{
name: "Element with attributes and children",
element: ElementSpec{
ID: "6",
TagName: "div",
Attributes: map[string]string{
"class": "container",
},
Children: []ElementSpec{
{
ID: "7",
TagName: "p",
Text: "Paragraph",
},
},
},
expected: `<div class="container" id="6"><p id="7">Paragraph</p></div>`,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.element.ContentStr()
if result != tt.expected {
t.Errorf("got %s, want %s", result, tt.expected)
}
})
}
}
154 changes: 73 additions & 81 deletions locatr/locatr.go → core/locatr.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package locatr
package core

import (
_ "embed"
Expand Down Expand Up @@ -73,37 +73,6 @@ func NewBaseLocatr(plugin PluginInterface, llmClient LlmClient, options BaseLoca
initilized: false,
}
}
func (l *BaseLocatr) getCurrentUrl() string {
if value, err := l.plugin.EvaluateJsFunction("window.location.href"); err == nil {
return value
}
return ""
}

func (al *BaseLocatr) locateElementId(htmlDOM string, userReq string) (string, error) {
systemPrompt := LOCATE_ELEMENT_PROMPT
jsonData, err := json.Marshal(&llmWebInputDto{
HtmlDom: htmlDOM,
UserReq: userReq,
})
if err != nil {
return "", fmt.Errorf("failed to marshal llmWebInputDto json: %v", err)
}

prompt := fmt.Sprintf("%s%s", string(systemPrompt), string(jsonData))

llmResponse, err := al.llmClient.ChatCompletion(prompt)
if err != nil {
return "", fmt.Errorf("failed to get response from LLM: %v", err)
}

llmLocatorOutput := &llmLocatorOutputDto{}
if err = json.Unmarshal([]byte(llmResponse), llmLocatorOutput); err != nil {
return "", fmt.Errorf("failed to unmarshal llmLocatorOutputDto json: %v", err)
}

return llmLocatorOutput.LocatorID, nil
}

func (l *BaseLocatr) addCachedLocatrs(url string, locatrName string, locatrs []string) {
if _, ok := l.cachedLocatrs[url]; !ok {
Expand Down Expand Up @@ -133,6 +102,49 @@ func (l *BaseLocatr) initilizeState() {
log.Println("Cache loaded successfully")
l.initilized = true
}
func (l *BaseLocatr) getLocatrsFromState(key string, currentUrl string) ([]string, error) {
if locatrs, ok := l.cachedLocatrs[currentUrl]; ok {
for _, v := range locatrs {
if v.LocatrName == key {
return v.Locatrs, nil
}
}
}
return nil, errors.New("key not found")
}
func (l *BaseLocatr) loadLocatorsCache(cachePath string) error {
file, err := os.Open(cachePath)
if err != nil {
return nil // ignore this error for now
}
defer file.Close()
byteValue, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("failed to read cache file (%s): %v", cachePath, err)
}
err = json.Unmarshal(byteValue, &l.cachedLocatrs)
if err != nil {
return fmt.Errorf("failed to unmarshal cache file (%s): %v", cachePath, err)
}
return nil
}
func writeLocatorsToCache(cachePath string, cacheString []byte) error {
err := os.MkdirAll(filepath.Dir(cachePath), 0755)
if err != nil {
return fmt.Errorf("failed to create directory: %v", err)
}

file, err := os.OpenFile(cachePath, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("failed to create file: %v", err)
}
defer file.Close()
if _, err := file.Write(cacheString); err != nil {
return fmt.Errorf("failed to write cache: %v", err)
}

return nil
}

func (l *BaseLocatr) GetLocatorStr(userReq string) (string, error) {
if err := l.plugin.EvaluateJsScript(HTML_MINIFIER_JS_CONTENTT); err != nil {
Expand All @@ -141,7 +153,7 @@ func (l *BaseLocatr) GetLocatorStr(userReq string) (string, error) {
l.initilizeState()
log.Println("Searching for locator in cache")
currnetUrl := l.getCurrentUrl()
locators, err := l.getLocatrsFromState(userReq)
locators, err := l.getLocatrsFromState(userReq, currnetUrl)

if err == nil && len(locators) > 0 {
validLocator, err := l.getValidLocator(locators)
Expand Down Expand Up @@ -187,55 +199,11 @@ func (l *BaseLocatr) GetLocatorStr(userReq string) (string, error) {
return validLocators, nil

}

func writeLocatorsToCache(cachePath string, cacheString []byte) error {
err := os.MkdirAll(filepath.Dir(cachePath), 0755)
if err != nil {
return fmt.Errorf("failed to create directory: %v", err)
}

file, err := os.OpenFile(cachePath, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("failed to create file: %v", err)
}
defer file.Close()
if _, err := file.Write(cacheString); err != nil {
return fmt.Errorf("failed to write cache: %v", err)
}

if err != nil {
return fmt.Errorf("failed to write record: %v", err)
}

return nil
}

func (l *BaseLocatr) loadLocatorsCache(cachePath string) error {
file, err := os.Open(cachePath)
if err != nil {
return nil // ignore this error for now
}
defer file.Close()
byteValue, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("failed to read cache file (%s): %v", cachePath, err)
}
err = json.Unmarshal(byteValue, &l.cachedLocatrs)
if err != nil {
return fmt.Errorf("failed to unmarshal cache file (%s): %v", cachePath, err)
}
return nil
}

func (l *BaseLocatr) getLocatrsFromState(key string) ([]string, error) {
if locatrs, ok := l.cachedLocatrs[l.getCurrentUrl()]; ok {
for _, v := range locatrs {
if v.LocatrName == key {
return v.Locatrs, nil
}
}
func (l *BaseLocatr) getCurrentUrl() string {
if value, err := l.plugin.EvaluateJsFunction("window.location.href"); err == nil {
return value
}
return nil, errors.New("key not found")
return ""
}

func (l *BaseLocatr) getMinifiedDomAndLocatorMap() (*ElementSpec, *IdToLocatorMap, error) {
Expand All @@ -262,3 +230,27 @@ func (l *BaseLocatr) getValidLocator(locators []string) (string, error) {
}
return "", ErrUnableToFindValidLocator
}
func (al *BaseLocatr) locateElementId(htmlDOM string, userReq string) (string, error) {
systemPrompt := LOCATE_ELEMENT_PROMPT
jsonData, err := json.Marshal(&llmWebInputDto{
HtmlDom: htmlDOM,
UserReq: userReq,
})
if err != nil {
return "", fmt.Errorf("failed to marshal llmWebInputDto json: %v", err)
}

prompt := fmt.Sprintf("%s%s", string(systemPrompt), string(jsonData))

llmResponse, err := al.llmClient.ChatCompletion(prompt)
if err != nil {
return "", fmt.Errorf("failed to get response from LLM: %v", err)
}

llmLocatorOutput := &llmLocatorOutputDto{}
if err = json.Unmarshal([]byte(llmResponse), llmLocatorOutput); err != nil {
return "", fmt.Errorf("failed to unmarshal llmLocatorOutputDto json: %v", err)
}

return llmLocatorOutput.LocatorID, nil
}
Loading

0 comments on commit 10bc856

Please sign in to comment.