// Package extractortest provides mock implementations of the extractor // interfaces for use in unit tests. The mocks support selector-based // responses so site extractors can exercise their parsing logic without // a real browser. package extractortest import ( "context" "fmt" "time" "gitea.stevedudenhoeffer.com/steve/go-extractor" ) // MockNode implements extractor.Node with configurable selector responses. type MockNode struct { TextValue string TextErr error ContentValue string Attrs map[string]string // Children maps CSS selectors to the nodes that should be returned. Children map[string]extractor.Nodes } var _ extractor.Node = &MockNode{} func (m *MockNode) Content() (string, error) { return m.ContentValue, nil } func (m *MockNode) Text() (string, error) { return m.TextValue, m.TextErr } func (m *MockNode) Attr(name string) (string, error) { if m.Attrs == nil { return "", nil } v, ok := m.Attrs[name] if !ok { return "", nil } return v, nil } func (m *MockNode) Screenshot() ([]byte, error) { return nil, nil } func (m *MockNode) Type(_ string) error { return nil } func (m *MockNode) Click() error { return nil } func (m *MockNode) SetHidden(_ bool) error { return nil } func (m *MockNode) SetAttribute(_, _ string) error { return nil } func (m *MockNode) Select(selector string) extractor.Nodes { if m.Children == nil { return nil } return m.Children[selector] } func (m *MockNode) SelectFirst(selector string) extractor.Node { return m.Select(selector).First() } func (m *MockNode) ForEach(selector string, fn func(extractor.Node) error) error { nodes := m.Select(selector) for _, n := range nodes { if err := fn(n); err != nil { return err } } return nil } // MockDocument implements extractor.Document with configurable selector responses. type MockDocument struct { MockNode URLValue string } var _ extractor.Document = &MockDocument{} func (m *MockDocument) URL() string { return m.URLValue } func (m *MockDocument) Refresh() error { return nil } func (m *MockDocument) Close() error { return nil } func (m *MockDocument) WaitForNetworkIdle(_ *time.Duration) error { return nil } // Content on MockDocument returns its own ContentValue (overrides embedded MockNode). func (m *MockDocument) Content() (string, error) { return m.ContentValue, nil } // MockBrowser implements extractor.Browser. Configure Documents to map URLs // to MockDocuments that will be returned from Open. type MockBrowser struct { Documents map[string]*MockDocument } var _ extractor.Browser = &MockBrowser{} func (m *MockBrowser) Close() error { return nil } func (m *MockBrowser) Open(_ context.Context, url string, _ extractor.OpenPageOptions) (extractor.Document, error) { if m.Documents == nil { return nil, fmt.Errorf("no documents configured") } doc, ok := m.Documents[url] if !ok { return nil, fmt.Errorf("no mock document for URL %q", url) } return doc, nil }