REFACTOR: split webserver/server_test.go
into a bunch of different files, by handler
This commit is contained in:
parent
5b8d110474
commit
854cfb6d7a
46
internal/webserver/handler_bookmarks_test.go
Normal file
46
internal/webserver/handler_bookmarks_test.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/andybalholm/cascadia"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
|
||||||
|
"gitlab.com/offline-twitter/twitter_offline_engine/internal/webserver"
|
||||||
|
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBookmarksTab(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// Boilerplate for setting an active user
|
||||||
|
app := webserver.NewApp(profile)
|
||||||
|
app.IsScrapingDisabled = true
|
||||||
|
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/bookmarks", nil))
|
||||||
|
resp := recorder.Result()
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweets, 2)
|
||||||
|
|
||||||
|
// Double check pagination works properly
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/bookmarks?cursor=1800452344077464795", nil))
|
||||||
|
resp = recorder.Result()
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
tweets = cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweets, 1)
|
||||||
|
}
|
60
internal/webserver/handler_follow_unfollow_test.go
Normal file
60
internal/webserver/handler_follow_unfollow_test.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/andybalholm/cascadia"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: deprecated-offline-follows
|
||||||
|
|
||||||
|
func TestFollowUnfollow(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
user, err := profile.GetUserByHandle("kwamurai")
|
||||||
|
require.NoError(err)
|
||||||
|
require.False(user.IsFollowed)
|
||||||
|
|
||||||
|
// Follow the user
|
||||||
|
resp := do_request(httptest.NewRequest("POST", "/follow/kwamurai", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
button := cascadia.Query(root, selector("button"))
|
||||||
|
assert.Contains(button.Attr, html.Attribute{Key: "hx-post", Val: "/unfollow/kwamurai"})
|
||||||
|
assert.Equal(strings.TrimSpace(button.FirstChild.Data), "Unfollow")
|
||||||
|
|
||||||
|
user, err = profile.GetUserByHandle("kwamurai")
|
||||||
|
require.NoError(err)
|
||||||
|
require.True(user.IsFollowed)
|
||||||
|
|
||||||
|
// Unfollow the user
|
||||||
|
resp = do_request(httptest.NewRequest("POST", "/unfollow/kwamurai", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
button = cascadia.Query(root, selector("button"))
|
||||||
|
assert.Contains(button.Attr, html.Attribute{Key: "hx-post", Val: "/follow/kwamurai"})
|
||||||
|
assert.Equal(strings.TrimSpace(button.FirstChild.Data), "Follow")
|
||||||
|
|
||||||
|
user, err = profile.GetUserByHandle("kwamurai")
|
||||||
|
require.NoError(err)
|
||||||
|
require.False(user.IsFollowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFollowUnfollowPostOnly(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/follow/kwamurai", nil))
|
||||||
|
require.Equal(resp.StatusCode, 405)
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/unfollow/kwamurai", nil))
|
||||||
|
require.Equal(resp.StatusCode, 405)
|
||||||
|
}
|
114
internal/webserver/handler_lists_test.go
Normal file
114
internal/webserver/handler_lists_test.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/andybalholm/cascadia"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestListsIndex(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/lists", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
// Check that there's at least 2 Lists
|
||||||
|
assert.True(t, len(cascadia.QueryAll(root, selector(".list-preview"))) >= 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListDetail(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
// Users
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/lists/1/users", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".users-list .author-info")), 5)
|
||||||
|
|
||||||
|
// Feed
|
||||||
|
resp1 := do_request(httptest.NewRequest("GET", "/lists/2", nil))
|
||||||
|
require.Equal(resp1.StatusCode, 200)
|
||||||
|
root1, err := html.Parse(resp1.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root1, selector(".timeline > .tweet")), 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListDetailDoesntExist(t *testing.T) {
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/lists/2523478", nil))
|
||||||
|
require.Equal(t, resp.StatusCode, 404)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListDetailInvalidId(t *testing.T) {
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/lists/asd", nil))
|
||||||
|
require.Equal(t, resp.StatusCode, 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListAddAndDeleteUser(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
// Initial
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/lists/2/users", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".users-list .author-info")), 2)
|
||||||
|
|
||||||
|
// Add a user
|
||||||
|
resp_add := do_request(httptest.NewRequest("GET", "/lists/2/add_user?user_handle=cernovich", nil))
|
||||||
|
require.Equal(resp_add.StatusCode, 302)
|
||||||
|
require.Equal("/lists/2/users", resp_add.Header.Get("Location"))
|
||||||
|
|
||||||
|
// Should be +1 user now
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/lists/2/users", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".users-list .author-info")), 3)
|
||||||
|
|
||||||
|
// Delete a user
|
||||||
|
resp_remove := do_request(httptest.NewRequest("GET", "/lists/2/remove_user?user_handle=cernovich", nil))
|
||||||
|
require.Equal(resp_remove.StatusCode, 302)
|
||||||
|
require.Equal("/lists/2/users", resp_remove.Header.Get("Location"))
|
||||||
|
|
||||||
|
// Should be +1 user now
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/lists/2/users", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".users-list .author-info")), 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateNewList(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
// Initial list-of-lists
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/lists", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
num_lists := len(cascadia.QueryAll(root, selector(".list-preview")))
|
||||||
|
|
||||||
|
// Create a new list
|
||||||
|
resp_add := do_request(httptest.NewRequest("POST", "/lists", strings.NewReader(`{"name": "My New List"}`)))
|
||||||
|
require.Equal(resp_add.StatusCode, 302)
|
||||||
|
require.Equal(fmt.Sprintf("/lists/%d/users", num_lists+1), resp_add.Header.Get("Location"))
|
||||||
|
|
||||||
|
// Should be N+1 lists now
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/lists", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".list-preview")), num_lists+1)
|
||||||
|
}
|
157
internal/webserver/handler_messages_test.go
Normal file
157
internal/webserver/handler_messages_test.go
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/andybalholm/cascadia"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
|
||||||
|
"gitlab.com/offline-twitter/twitter_offline_engine/internal/webserver"
|
||||||
|
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Loading the index page should work if you're logged in
|
||||||
|
func TestMessagesIndexPage(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// Boilerplate for setting an active user
|
||||||
|
app := webserver.NewApp(profile)
|
||||||
|
app.IsScrapingDisabled = true
|
||||||
|
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
||||||
|
|
||||||
|
// Chat list
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/messages", nil))
|
||||||
|
resp := recorder.Result()
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".chat-list .chat-list-entry")), 2)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".chat-view .dm-message")), 0) // No messages until you click on one
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a chat room
|
||||||
|
func TestMessagesRoom(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// Boilerplate for setting an active user
|
||||||
|
app := webserver.NewApp(profile)
|
||||||
|
app.IsScrapingDisabled = true
|
||||||
|
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
||||||
|
|
||||||
|
// Chat detail
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/messages/1488963321701171204-1178839081222115328", nil))
|
||||||
|
resp := recorder.Result()
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".chat-list .chat-list-entry")), 2) // Chat list still renders
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector("#chat-view .dm-message")), 5)
|
||||||
|
|
||||||
|
// Should have the poller at the bottom
|
||||||
|
poller := cascadia.Query(root, selector("#new-messages-poller"))
|
||||||
|
assert.NotNil(poller)
|
||||||
|
assert.Contains(poller.Attr, html.Attribute{Key: "hx-get", Val: "/messages/1488963321701171204-1178839081222115328"})
|
||||||
|
assert.Contains(
|
||||||
|
cascadia.Query(poller, selector("input[name='scroll_bottom']")).Attr,
|
||||||
|
html.Attribute{Key: "value", Val: "1"},
|
||||||
|
)
|
||||||
|
assert.Contains(
|
||||||
|
cascadia.Query(poller, selector("input[name='latest_timestamp']")).Attr,
|
||||||
|
html.Attribute{Key: "value", Val: "1686025129144"},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading the page since a given message
|
||||||
|
func TestMessagesRoomPollForUpdates(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// Boilerplate for setting an active user
|
||||||
|
app := webserver.NewApp(profile)
|
||||||
|
app.IsScrapingDisabled = true
|
||||||
|
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
||||||
|
|
||||||
|
// Chat detail
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
req := httptest.NewRequest("GET", "/messages/1488963321701171204-1178839081222115328?poll&latest_timestamp=1686025129141", nil)
|
||||||
|
req.Header.Set("HX-Request", "true")
|
||||||
|
app.ServeHTTP(recorder, req)
|
||||||
|
resp := recorder.Result()
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".dm-message")), 3)
|
||||||
|
|
||||||
|
// Should have the poller at the bottom
|
||||||
|
poller := cascadia.Query(root, selector("#new-messages-poller"))
|
||||||
|
assert.NotNil(poller)
|
||||||
|
assert.Contains(poller.Attr, html.Attribute{Key: "hx-get", Val: "/messages/1488963321701171204-1178839081222115328"})
|
||||||
|
assert.Contains(
|
||||||
|
cascadia.Query(poller, selector("input[name='scroll_bottom']")).Attr,
|
||||||
|
html.Attribute{Key: "value", Val: "1"},
|
||||||
|
)
|
||||||
|
assert.Contains(
|
||||||
|
cascadia.Query(poller, selector("input[name='latest_timestamp']")).Attr,
|
||||||
|
html.Attribute{Key: "value", Val: "1686025129144"},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading the page since latest message (no updates)
|
||||||
|
func TestMessagesRoomPollForUpdatesEmptyResult(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// Boilerplate for setting an active user
|
||||||
|
app := webserver.NewApp(profile)
|
||||||
|
app.IsScrapingDisabled = true
|
||||||
|
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
||||||
|
|
||||||
|
// Chat detail
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
req := httptest.NewRequest("GET", "/messages/1488963321701171204-1178839081222115328?poll&latest_timestamp=1686025129144", nil)
|
||||||
|
req.Header.Set("HX-Request", "true")
|
||||||
|
app.ServeHTTP(recorder, req)
|
||||||
|
resp := recorder.Result()
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".dm-message")), 0)
|
||||||
|
|
||||||
|
// Should have the poller at the bottom, with the same value as previously
|
||||||
|
poller := cascadia.Query(root, selector("#new-messages-poller"))
|
||||||
|
assert.NotNil(poller)
|
||||||
|
assert.Contains(poller.Attr, html.Attribute{Key: "hx-get", Val: "/messages/1488963321701171204-1178839081222115328"})
|
||||||
|
assert.Contains(
|
||||||
|
cascadia.Query(poller, selector("input[name='scroll_bottom']")).Attr,
|
||||||
|
html.Attribute{Key: "value", Val: "1"},
|
||||||
|
)
|
||||||
|
assert.Contains(
|
||||||
|
cascadia.Query(poller, selector("input[name='latest_timestamp']")).Attr,
|
||||||
|
html.Attribute{Key: "value", Val: "1686025129144"},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll back in the messages
|
||||||
|
func TestMessagesPaginate(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// Boilerplate for setting an active user
|
||||||
|
app := webserver.NewApp(profile)
|
||||||
|
app.IsScrapingDisabled = true
|
||||||
|
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
||||||
|
|
||||||
|
// Chat detail
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
req := httptest.NewRequest("GET", "/messages/1488963321701171204-1178839081222115328?cursor=1686025129142", nil)
|
||||||
|
req.Header.Set("HX-Request", "true")
|
||||||
|
app.ServeHTTP(recorder, req)
|
||||||
|
resp := recorder.Result()
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".dm-message")), 2)
|
||||||
|
}
|
44
internal/webserver/handler_notifications_test.go
Normal file
44
internal/webserver/handler_notifications_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/andybalholm/cascadia"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
|
||||||
|
"gitlab.com/offline-twitter/twitter_offline_engine/internal/webserver"
|
||||||
|
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNotifications(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// Boilerplate for setting an active user
|
||||||
|
app := webserver.NewApp(profile)
|
||||||
|
app.IsScrapingDisabled = true
|
||||||
|
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
||||||
|
|
||||||
|
// Notifications page
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
req := httptest.NewRequest("GET", "/notifications", nil)
|
||||||
|
app.ServeHTTP(recorder, req)
|
||||||
|
resp := recorder.Result()
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".notification")), 6)
|
||||||
|
|
||||||
|
// Show more
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest("GET", "/notifications?cursor=1726604756351", nil)
|
||||||
|
req.Header.Set("HX-Request", "true")
|
||||||
|
app.ServeHTTP(recorder, req)
|
||||||
|
resp = recorder.Result()
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".notification")), 5)
|
||||||
|
}
|
153
internal/webserver/handler_search_test.go
Normal file
153
internal/webserver/handler_search_test.go
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/andybalholm/cascadia"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSearchQueryStringRedirect(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/search?q=asdf", nil))
|
||||||
|
assert.Equal(resp.StatusCode, 302)
|
||||||
|
assert.Equal(resp.Header.Get("Location"), "/search/asdf")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearch(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
search_txt := "to:spacex to:covfefeanon"
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape(search_txt)), nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
title_node := cascadia.Query(root, selector("title"))
|
||||||
|
assert.Equal(title_node.FirstChild.Data, "Search | Offline Twitter")
|
||||||
|
assert.Contains(cascadia.Query(root, selector("#search-bar")).Attr, html.Attribute{Key: "value", Val: search_txt})
|
||||||
|
|
||||||
|
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweet_nodes, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchWithCursor(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// First, without the cursor
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/search/who%20are", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".timeline > .tweet")), 3)
|
||||||
|
|
||||||
|
// Add a cursor with the 1st tweet's posted_at time
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/search/who%20are?cursor=1628979529000", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".timeline > .tweet")), 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchWithSortOrder(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/search/think?sort-order=most%20likes", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Contains(cascadia.Query(root, selector("select[name='sort-order'] option[selected]")).FirstChild.Data, "most likes")
|
||||||
|
|
||||||
|
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
txts := []string{
|
||||||
|
"Morally nuanced and complicated discussion",
|
||||||
|
"a lot of y’all embarrass yourselves on this",
|
||||||
|
"this is why the \"think tank mindset\" is a dead end",
|
||||||
|
"At this point what can we expect I guess",
|
||||||
|
"Idk if this is relevant to your department",
|
||||||
|
}
|
||||||
|
for i, txt := range txts {
|
||||||
|
assert.Contains(cascadia.Query(tweets[i], selector("p.text")).FirstChild.Data, txt)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/search/think?sort-order=most%20likes&cursor=413", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
tweets = cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
for i, txt := range txts[2:] {
|
||||||
|
assert.Contains(cascadia.Query(tweets[i], selector("p.text")).FirstChild.Data, txt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchUsers(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/search/no?type=users", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
user_elements := cascadia.QueryAll(root, selector(".users-list .user"))
|
||||||
|
assert.Len(user_elements, 2)
|
||||||
|
assert.Contains(cascadia.Query(root, selector("#search-bar")).Attr, html.Attribute{Key: "value", Val: "no"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search bar pasted link redirects
|
||||||
|
// --------------------------------
|
||||||
|
|
||||||
|
func TestSearchRedirectOnUserHandle(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("@somebody")), nil))
|
||||||
|
assert.Equal(resp.StatusCode, 302)
|
||||||
|
assert.Equal(resp.Header.Get("Location"), "/somebody")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchRedirectOnTweetLink(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
// Desktop URL
|
||||||
|
resp := do_request(httptest.NewRequest("GET",
|
||||||
|
fmt.Sprintf("/search/%s", url.PathEscape("https://twitter.com/wispem_wantex/status/1695221528617468324")),
|
||||||
|
nil))
|
||||||
|
assert.Equal(resp.StatusCode, 302)
|
||||||
|
assert.Equal(resp.Header.Get("Location"), "/tweet/1695221528617468324")
|
||||||
|
|
||||||
|
// Mobile URL
|
||||||
|
resp = do_request(httptest.NewRequest("GET",
|
||||||
|
fmt.Sprintf("/search/%s", url.PathEscape("https://mobile.twitter.com/wispem_wantex/status/1695221528617468324")),
|
||||||
|
nil))
|
||||||
|
assert.Equal(resp.StatusCode, 302)
|
||||||
|
assert.Equal(resp.Header.Get("Location"), "/tweet/1695221528617468324")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchRedirectOnUserFeedLink(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
// Desktop URL
|
||||||
|
resp := do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("https://twitter.com/agsdf")), nil))
|
||||||
|
assert.Equal(resp.StatusCode, 302)
|
||||||
|
assert.Equal(resp.Header.Get("Location"), "/agsdf")
|
||||||
|
|
||||||
|
// "With Replies" page
|
||||||
|
resp = do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("https://x.com/agsdf/with_replies")), nil))
|
||||||
|
assert.Equal(resp.StatusCode, 302)
|
||||||
|
assert.Equal(resp.Header.Get("Location"), "/agsdf")
|
||||||
|
|
||||||
|
// Mobile URL
|
||||||
|
resp = do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("https://mobile.twitter.com/agsdfhh")), nil))
|
||||||
|
assert.Equal(resp.StatusCode, 302)
|
||||||
|
assert.Equal(resp.Header.Get("Location"), "/agsdfhh")
|
||||||
|
}
|
23
internal/webserver/handler_static_test.go
Normal file
23
internal/webserver/handler_static_test.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStaticFile(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/static/styles.css", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStaticFileNonexistent(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/static/blehblehblehwfe", nil))
|
||||||
|
require.Equal(resp.StatusCode, 404)
|
||||||
|
}
|
79
internal/webserver/handler_timeline_test.go
Normal file
79
internal/webserver/handler_timeline_test.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/andybalholm/cascadia"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
|
||||||
|
"gitlab.com/offline-twitter/twitter_offline_engine/internal/webserver"
|
||||||
|
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTimeline(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/timeline/offline", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
title_node := cascadia.Query(root, selector("title"))
|
||||||
|
assert.Equal(title_node.FirstChild.Data, "Timeline | Offline Twitter")
|
||||||
|
|
||||||
|
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweet_nodes, 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimelineWithCursor(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/timeline/offline?cursor=1631935701000", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
title_node := cascadia.Query(root, selector("title"))
|
||||||
|
assert.Equal(title_node.FirstChild.Data, "Timeline | Offline Twitter")
|
||||||
|
|
||||||
|
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweet_nodes, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimelineWithCursorBadNumber(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// With a cursor but it sucks
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/timeline/offline?cursor=asdf", nil))
|
||||||
|
require.Equal(resp.StatusCode, 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserFeedTimeline(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// Boilerplate for setting an active user
|
||||||
|
app := webserver.NewApp(profile)
|
||||||
|
app.IsScrapingDisabled = true
|
||||||
|
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
||||||
|
|
||||||
|
// Chat list
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/timeline", nil))
|
||||||
|
resp := recorder.Result()
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
title_node := cascadia.Query(root, selector("title"))
|
||||||
|
assert.Equal(title_node.FirstChild.Data, "Timeline | Offline Twitter")
|
||||||
|
|
||||||
|
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweet_nodes, 1)
|
||||||
|
}
|
141
internal/webserver/handler_tweet_detail_test.go
Normal file
141
internal/webserver/handler_tweet_detail_test.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/andybalholm/cascadia"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
|
||||||
|
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTweetDetail(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/tweet/1413773185296650241", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
tweet_nodes := cascadia.QueryAll(root, selector(".tweet"))
|
||||||
|
assert.Len(tweet_nodes, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTweetDetailMissing(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/tweet/100089", nil))
|
||||||
|
require.Equal(resp.StatusCode, 404)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTweetDetailInvalidNumber(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/tweet/fwjgkj", nil))
|
||||||
|
require.Equal(resp.StatusCode, 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTweetsWithContent(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// Poll
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/tweet/1465534109573390348", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".poll")), 1)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".poll__choice")), 4)
|
||||||
|
|
||||||
|
// Video
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/tweet/1453461248142495744", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector("video")), 1)
|
||||||
|
|
||||||
|
// Url
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/tweet/1438642143170646017", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".embedded-link")), 3)
|
||||||
|
|
||||||
|
// Space
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/tweet/1624833173514293249", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".space")), 1)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector("ul.space__participants-list li")), 9)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTweetWithEntities(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/tweet/1489944024278523906", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
entities := cascadia.QueryAll(root, selector(".entity"))
|
||||||
|
assert.Len(entities, 2)
|
||||||
|
assert.Equal(entities[0].Data, "a")
|
||||||
|
assert.Equal(entities[0].FirstChild.Data, "@gofundme")
|
||||||
|
assert.Contains(entities[0].Attr, html.Attribute{Key: "href", Val: "/gofundme"})
|
||||||
|
assert.Equal(entities[1].Data, "a")
|
||||||
|
assert.Equal(entities[1].FirstChild.Data, "#BankruptGoFundMe")
|
||||||
|
assert.Contains(entities[1].Attr, html.Attribute{Key: "href", Val: "/search/%23BankruptGoFundMe"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLongTweet(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/tweet/1695110851324256692", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
paragraphs := cascadia.QueryAll(root, selector(".tweet .text"))
|
||||||
|
assert.Len(paragraphs, 22)
|
||||||
|
|
||||||
|
twt, err := profile.GetTweetById(scraper.TweetID(1695110851324256692))
|
||||||
|
require.NoError(err)
|
||||||
|
for i, s := range strings.Split(twt.Text, "\n") {
|
||||||
|
assert.Equal(strings.TrimSpace(s), strings.TrimSpace(paragraphs[i].FirstChild.Data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTombstoneTweet(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/tweet/31", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
tombstone := cascadia.Query(root, selector(".tweet .tombstone"))
|
||||||
|
assert.Equal("This Tweet was deleted by the Tweet author", strings.TrimSpace(tombstone.FirstChild.Data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTweetThread(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/tweet/1698762403163304110", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
reply_chains := cascadia.QueryAll(root, selector(".reply-chain"))
|
||||||
|
require.Len(reply_chains, 2)
|
||||||
|
|
||||||
|
thread_chain := reply_chains[0]
|
||||||
|
assert.Len(cascadia.QueryAll(thread_chain, selector(".reply-tweet")), 7)
|
||||||
|
}
|
150
internal/webserver/handler_user_feed_test.go
Normal file
150
internal/webserver/handler_user_feed_test.go
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
package webserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/andybalholm/cascadia"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserFeed(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/cernovich", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
title_node := cascadia.Query(root, selector("title"))
|
||||||
|
assert.Equal(title_node.FirstChild.Data, "@Cernovich | Offline Twitter")
|
||||||
|
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".timeline > .tweet")), 8)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".timeline > .pinned-tweet")), 1)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".tweet")), 12) // Pinned tweet appears again
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserFeedWithEntityInBio(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/michaelmalice", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
bio_entities := cascadia.QueryAll(root, selector(".user-header__bio .entity"))
|
||||||
|
require.Len(bio_entities, 1)
|
||||||
|
assert.Equal(bio_entities[0].FirstChild.Data, "@SheathUnderwear")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserFeedMissing(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/awefhwefhwejh", nil))
|
||||||
|
require.Equal(resp.StatusCode, 404)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserFeedWithCursor(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// With a cursor
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/cernovich?cursor=1631935701000", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
title_node := cascadia.Query(root, selector("title"))
|
||||||
|
assert.Equal(title_node.FirstChild.Data, "@Cernovich | Offline Twitter")
|
||||||
|
|
||||||
|
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweet_nodes, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserFeedWithCursorBadNumber(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// With a cursor but it sucks
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/cernovich?cursor=asdf", nil))
|
||||||
|
require.Equal(resp.StatusCode, 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserFeedTweetsOnlyTab(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/Peter_Nimitz/without_replies", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweets, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserFeedMediaTab(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/Cernovich/media", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweets, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserFeedLikesTab(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/MysteryGrove/likes", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweets, 5)
|
||||||
|
|
||||||
|
// Double check pagination works properly
|
||||||
|
resp = do_request(httptest.NewRequest("GET", "/MysteryGrove/likes?cursor=5", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err = html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
tweets = cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
||||||
|
assert.Len(tweets, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Followers and followees
|
||||||
|
// -----------------------
|
||||||
|
|
||||||
|
func TestUserFollowers(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/Offline_Twatter/followers", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".users-list > .user")), 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserFollowees(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
resp := do_request(httptest.NewRequest("GET", "/Offline_Twatter/followees", nil))
|
||||||
|
require.Equal(resp.StatusCode, 200)
|
||||||
|
|
||||||
|
root, err := html.Parse(resp.Body)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Len(cascadia.QueryAll(root, selector(".users-list > .user")), 1)
|
||||||
|
}
|
@ -3,20 +3,14 @@ package webserver_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/andybalholm/cascadia"
|
"github.com/andybalholm/cascadia"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/net/html"
|
|
||||||
|
|
||||||
"gitlab.com/offline-twitter/twitter_offline_engine/internal/webserver"
|
"gitlab.com/offline-twitter/twitter_offline_engine/internal/webserver"
|
||||||
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/persistence"
|
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/persistence"
|
||||||
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CapturingWriter struct {
|
type CapturingWriter struct {
|
||||||
@ -65,855 +59,3 @@ func TestHomepage(t *testing.T) {
|
|||||||
require.Equal(resp.StatusCode, 303)
|
require.Equal(resp.StatusCode, 303)
|
||||||
require.Equal(resp.Header.Get("Location"), "/timeline")
|
require.Equal(resp.Header.Get("Location"), "/timeline")
|
||||||
}
|
}
|
||||||
|
|
||||||
// User feed
|
|
||||||
// ---------
|
|
||||||
|
|
||||||
func TestUserFeed(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/cernovich", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
title_node := cascadia.Query(root, selector("title"))
|
|
||||||
assert.Equal(title_node.FirstChild.Data, "@Cernovich | Offline Twitter")
|
|
||||||
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".timeline > .tweet")), 8)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".timeline > .pinned-tweet")), 1)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".tweet")), 12) // Pinned tweet appears again
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserFeedWithEntityInBio(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/michaelmalice", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
bio_entities := cascadia.QueryAll(root, selector(".user-header__bio .entity"))
|
|
||||||
require.Len(bio_entities, 1)
|
|
||||||
assert.Equal(bio_entities[0].FirstChild.Data, "@SheathUnderwear")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserFeedMissing(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/awefhwefhwejh", nil))
|
|
||||||
require.Equal(resp.StatusCode, 404)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserFeedWithCursor(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// With a cursor
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/cernovich?cursor=1631935701000", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
title_node := cascadia.Query(root, selector("title"))
|
|
||||||
assert.Equal(title_node.FirstChild.Data, "@Cernovich | Offline Twitter")
|
|
||||||
|
|
||||||
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweet_nodes, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserFeedWithCursorBadNumber(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// With a cursor but it sucks
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/cernovich?cursor=asdf", nil))
|
|
||||||
require.Equal(resp.StatusCode, 400)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserFeedTweetsOnlyTab(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/Peter_Nimitz/without_replies", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweets, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserFeedMediaTab(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/Cernovich/media", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweets, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserFeedLikesTab(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/MysteryGrove/likes", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweets, 5)
|
|
||||||
|
|
||||||
// Double check pagination works properly
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/MysteryGrove/likes?cursor=5", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
tweets = cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweets, 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBookmarksTab(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// Boilerplate for setting an active user
|
|
||||||
app := webserver.NewApp(profile)
|
|
||||||
app.IsScrapingDisabled = true
|
|
||||||
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/bookmarks", nil))
|
|
||||||
resp := recorder.Result()
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweets, 2)
|
|
||||||
|
|
||||||
// Double check pagination works properly
|
|
||||||
recorder = httptest.NewRecorder()
|
|
||||||
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/bookmarks?cursor=1800452344077464795", nil))
|
|
||||||
resp = recorder.Result()
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
tweets = cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweets, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Followers and followees
|
|
||||||
// -----------------------
|
|
||||||
|
|
||||||
func TestUserFollowers(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/Offline_Twatter/followers", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".users-list > .user")), 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserFollowees(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/Offline_Twatter/followees", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".users-list > .user")), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timeline page
|
|
||||||
// -------------
|
|
||||||
|
|
||||||
func TestTimeline(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/timeline/offline", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
title_node := cascadia.Query(root, selector("title"))
|
|
||||||
assert.Equal(title_node.FirstChild.Data, "Timeline | Offline Twitter")
|
|
||||||
|
|
||||||
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweet_nodes, 20)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTimelineWithCursor(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/timeline/offline?cursor=1631935701000", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
title_node := cascadia.Query(root, selector("title"))
|
|
||||||
assert.Equal(title_node.FirstChild.Data, "Timeline | Offline Twitter")
|
|
||||||
|
|
||||||
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweet_nodes, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTimelineWithCursorBadNumber(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// With a cursor but it sucks
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/timeline/offline?cursor=asdf", nil))
|
|
||||||
require.Equal(resp.StatusCode, 400)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserFeedTimeline(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// Boilerplate for setting an active user
|
|
||||||
app := webserver.NewApp(profile)
|
|
||||||
app.IsScrapingDisabled = true
|
|
||||||
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
|
||||||
|
|
||||||
// Chat list
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/timeline", nil))
|
|
||||||
resp := recorder.Result()
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
title_node := cascadia.Query(root, selector("title"))
|
|
||||||
assert.Equal(title_node.FirstChild.Data, "Timeline | Offline Twitter")
|
|
||||||
|
|
||||||
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweet_nodes, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search page
|
|
||||||
// -----------
|
|
||||||
|
|
||||||
func TestSearchQueryStringRedirect(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/search?q=asdf", nil))
|
|
||||||
assert.Equal(resp.StatusCode, 302)
|
|
||||||
assert.Equal(resp.Header.Get("Location"), "/search/asdf")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearch(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
search_txt := "to:spacex to:covfefeanon"
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape(search_txt)), nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
title_node := cascadia.Query(root, selector("title"))
|
|
||||||
assert.Equal(title_node.FirstChild.Data, "Search | Offline Twitter")
|
|
||||||
assert.Contains(cascadia.Query(root, selector("#search-bar")).Attr, html.Attribute{Key: "value", Val: search_txt})
|
|
||||||
|
|
||||||
tweet_nodes := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
assert.Len(tweet_nodes, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchWithCursor(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// First, without the cursor
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/search/who%20are", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".timeline > .tweet")), 3)
|
|
||||||
|
|
||||||
// Add a cursor with the 1st tweet's posted_at time
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/search/who%20are?cursor=1628979529000", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".timeline > .tweet")), 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchWithSortOrder(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/search/think?sort-order=most%20likes", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Contains(cascadia.Query(root, selector("select[name='sort-order'] option[selected]")).FirstChild.Data, "most likes")
|
|
||||||
|
|
||||||
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
txts := []string{
|
|
||||||
"Morally nuanced and complicated discussion",
|
|
||||||
"a lot of y’all embarrass yourselves on this",
|
|
||||||
"this is why the \"think tank mindset\" is a dead end",
|
|
||||||
"At this point what can we expect I guess",
|
|
||||||
"Idk if this is relevant to your department",
|
|
||||||
}
|
|
||||||
for i, txt := range txts {
|
|
||||||
assert.Contains(cascadia.Query(tweets[i], selector("p.text")).FirstChild.Data, txt)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/search/think?sort-order=most%20likes&cursor=413", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
tweets = cascadia.QueryAll(root, selector(".timeline > .tweet"))
|
|
||||||
for i, txt := range txts[2:] {
|
|
||||||
assert.Contains(cascadia.Query(tweets[i], selector("p.text")).FirstChild.Data, txt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchUsers(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/search/no?type=users", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
user_elements := cascadia.QueryAll(root, selector(".users-list .user"))
|
|
||||||
assert.Len(user_elements, 2)
|
|
||||||
assert.Contains(cascadia.Query(root, selector("#search-bar")).Attr, html.Attribute{Key: "value", Val: "no"})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search bar pasted link redirects
|
|
||||||
// --------------------------------
|
|
||||||
|
|
||||||
func TestSearchRedirectOnUserHandle(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("@somebody")), nil))
|
|
||||||
assert.Equal(resp.StatusCode, 302)
|
|
||||||
assert.Equal(resp.Header.Get("Location"), "/somebody")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchRedirectOnTweetLink(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
// Desktop URL
|
|
||||||
resp := do_request(httptest.NewRequest("GET",
|
|
||||||
fmt.Sprintf("/search/%s", url.PathEscape("https://twitter.com/wispem_wantex/status/1695221528617468324")),
|
|
||||||
nil))
|
|
||||||
assert.Equal(resp.StatusCode, 302)
|
|
||||||
assert.Equal(resp.Header.Get("Location"), "/tweet/1695221528617468324")
|
|
||||||
|
|
||||||
// Mobile URL
|
|
||||||
resp = do_request(httptest.NewRequest("GET",
|
|
||||||
fmt.Sprintf("/search/%s", url.PathEscape("https://mobile.twitter.com/wispem_wantex/status/1695221528617468324")),
|
|
||||||
nil))
|
|
||||||
assert.Equal(resp.StatusCode, 302)
|
|
||||||
assert.Equal(resp.Header.Get("Location"), "/tweet/1695221528617468324")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchRedirectOnUserFeedLink(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
// Desktop URL
|
|
||||||
resp := do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("https://twitter.com/agsdf")), nil))
|
|
||||||
assert.Equal(resp.StatusCode, 302)
|
|
||||||
assert.Equal(resp.Header.Get("Location"), "/agsdf")
|
|
||||||
|
|
||||||
// "With Replies" page
|
|
||||||
resp = do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("https://x.com/agsdf/with_replies")), nil))
|
|
||||||
assert.Equal(resp.StatusCode, 302)
|
|
||||||
assert.Equal(resp.Header.Get("Location"), "/agsdf")
|
|
||||||
|
|
||||||
// Mobile URL
|
|
||||||
resp = do_request(httptest.NewRequest("GET", fmt.Sprintf("/search/%s", url.PathEscape("https://mobile.twitter.com/agsdfhh")), nil))
|
|
||||||
assert.Equal(resp.StatusCode, 302)
|
|
||||||
assert.Equal(resp.Header.Get("Location"), "/agsdfhh")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tweet Detail page
|
|
||||||
// -----------------
|
|
||||||
|
|
||||||
func TestTweetDetail(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/tweet/1413773185296650241", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
tweet_nodes := cascadia.QueryAll(root, selector(".tweet"))
|
|
||||||
assert.Len(tweet_nodes, 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTweetDetailMissing(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/tweet/100089", nil))
|
|
||||||
require.Equal(resp.StatusCode, 404)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTweetDetailInvalidNumber(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/tweet/fwjgkj", nil))
|
|
||||||
require.Equal(resp.StatusCode, 400)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTweetsWithContent(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// Poll
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/tweet/1465534109573390348", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".poll")), 1)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".poll__choice")), 4)
|
|
||||||
|
|
||||||
// Video
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/tweet/1453461248142495744", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector("video")), 1)
|
|
||||||
|
|
||||||
// Url
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/tweet/1438642143170646017", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".embedded-link")), 3)
|
|
||||||
|
|
||||||
// Space
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/tweet/1624833173514293249", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".space")), 1)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector("ul.space__participants-list li")), 9)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTweetWithEntities(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/tweet/1489944024278523906", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
entities := cascadia.QueryAll(root, selector(".entity"))
|
|
||||||
assert.Len(entities, 2)
|
|
||||||
assert.Equal(entities[0].Data, "a")
|
|
||||||
assert.Equal(entities[0].FirstChild.Data, "@gofundme")
|
|
||||||
assert.Contains(entities[0].Attr, html.Attribute{Key: "href", Val: "/gofundme"})
|
|
||||||
assert.Equal(entities[1].Data, "a")
|
|
||||||
assert.Equal(entities[1].FirstChild.Data, "#BankruptGoFundMe")
|
|
||||||
assert.Contains(entities[1].Attr, html.Attribute{Key: "href", Val: "/search/%23BankruptGoFundMe"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLongTweet(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/tweet/1695110851324256692", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
paragraphs := cascadia.QueryAll(root, selector(".tweet .text"))
|
|
||||||
assert.Len(paragraphs, 22)
|
|
||||||
|
|
||||||
twt, err := profile.GetTweetById(scraper.TweetID(1695110851324256692))
|
|
||||||
require.NoError(err)
|
|
||||||
for i, s := range strings.Split(twt.Text, "\n") {
|
|
||||||
assert.Equal(strings.TrimSpace(s), strings.TrimSpace(paragraphs[i].FirstChild.Data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTombstoneTweet(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/tweet/31", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
tombstone := cascadia.Query(root, selector(".tweet .tombstone"))
|
|
||||||
assert.Equal("This Tweet was deleted by the Tweet author", strings.TrimSpace(tombstone.FirstChild.Data))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTweetThread(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/tweet/1698762403163304110", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
|
|
||||||
reply_chains := cascadia.QueryAll(root, selector(".reply-chain"))
|
|
||||||
require.Len(reply_chains, 2)
|
|
||||||
|
|
||||||
thread_chain := reply_chains[0]
|
|
||||||
assert.Len(cascadia.QueryAll(thread_chain, selector(".reply-tweet")), 7)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Follow and unfollow
|
|
||||||
// -------------------
|
|
||||||
|
|
||||||
func TestFollowUnfollow(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
user, err := profile.GetUserByHandle("kwamurai")
|
|
||||||
require.NoError(err)
|
|
||||||
require.False(user.IsFollowed)
|
|
||||||
|
|
||||||
// Follow the user
|
|
||||||
resp := do_request(httptest.NewRequest("POST", "/follow/kwamurai", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
button := cascadia.Query(root, selector("button"))
|
|
||||||
assert.Contains(button.Attr, html.Attribute{Key: "hx-post", Val: "/unfollow/kwamurai"})
|
|
||||||
assert.Equal(strings.TrimSpace(button.FirstChild.Data), "Unfollow")
|
|
||||||
|
|
||||||
user, err = profile.GetUserByHandle("kwamurai")
|
|
||||||
require.NoError(err)
|
|
||||||
require.True(user.IsFollowed)
|
|
||||||
|
|
||||||
// Unfollow the user
|
|
||||||
resp = do_request(httptest.NewRequest("POST", "/unfollow/kwamurai", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
button = cascadia.Query(root, selector("button"))
|
|
||||||
assert.Contains(button.Attr, html.Attribute{Key: "hx-post", Val: "/follow/kwamurai"})
|
|
||||||
assert.Equal(strings.TrimSpace(button.FirstChild.Data), "Follow")
|
|
||||||
|
|
||||||
user, err = profile.GetUserByHandle("kwamurai")
|
|
||||||
require.NoError(err)
|
|
||||||
require.False(user.IsFollowed)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFollowUnfollowPostOnly(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/follow/kwamurai", nil))
|
|
||||||
require.Equal(resp.StatusCode, 405)
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/unfollow/kwamurai", nil))
|
|
||||||
require.Equal(resp.StatusCode, 405)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Static content
|
|
||||||
// --------------
|
|
||||||
|
|
||||||
func TestStaticFile(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/static/styles.css", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStaticFileNonexistent(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/static/blehblehblehwfe", nil))
|
|
||||||
require.Equal(resp.StatusCode, 404)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lists
|
|
||||||
// -----
|
|
||||||
|
|
||||||
func TestListsIndex(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/lists", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
|
|
||||||
// Check that there's at least 2 Lists
|
|
||||||
assert.True(t, len(cascadia.QueryAll(root, selector(".list-preview"))) >= 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListDetail(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
// Users
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/lists/1/users", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".users-list .author-info")), 5)
|
|
||||||
|
|
||||||
// Feed
|
|
||||||
resp1 := do_request(httptest.NewRequest("GET", "/lists/2", nil))
|
|
||||||
require.Equal(resp1.StatusCode, 200)
|
|
||||||
root1, err := html.Parse(resp1.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root1, selector(".timeline > .tweet")), 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListDetailDoesntExist(t *testing.T) {
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/lists/2523478", nil))
|
|
||||||
require.Equal(t, resp.StatusCode, 404)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListDetailInvalidId(t *testing.T) {
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/lists/asd", nil))
|
|
||||||
require.Equal(t, resp.StatusCode, 400)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListAddAndDeleteUser(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
// Initial
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/lists/2/users", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".users-list .author-info")), 2)
|
|
||||||
|
|
||||||
// Add a user
|
|
||||||
resp_add := do_request(httptest.NewRequest("GET", "/lists/2/add_user?user_handle=cernovich", nil))
|
|
||||||
require.Equal(resp_add.StatusCode, 302)
|
|
||||||
require.Equal("/lists/2/users", resp_add.Header.Get("Location"))
|
|
||||||
|
|
||||||
// Should be +1 user now
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/lists/2/users", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".users-list .author-info")), 3)
|
|
||||||
|
|
||||||
// Delete a user
|
|
||||||
resp_remove := do_request(httptest.NewRequest("GET", "/lists/2/remove_user?user_handle=cernovich", nil))
|
|
||||||
require.Equal(resp_remove.StatusCode, 302)
|
|
||||||
require.Equal("/lists/2/users", resp_remove.Header.Get("Location"))
|
|
||||||
|
|
||||||
// Should be +1 user now
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/lists/2/users", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".users-list .author-info")), 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateNewList(t *testing.T) {
|
|
||||||
require := require.New(t)
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
// Initial list-of-lists
|
|
||||||
resp := do_request(httptest.NewRequest("GET", "/lists", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
num_lists := len(cascadia.QueryAll(root, selector(".list-preview")))
|
|
||||||
|
|
||||||
// Create a new list
|
|
||||||
resp_add := do_request(httptest.NewRequest("POST", "/lists", strings.NewReader(`{"name": "My New List"}`)))
|
|
||||||
require.Equal(resp_add.StatusCode, 302)
|
|
||||||
require.Equal(fmt.Sprintf("/lists/%d/users", num_lists+1), resp_add.Header.Get("Location"))
|
|
||||||
|
|
||||||
// Should be N+1 lists now
|
|
||||||
resp = do_request(httptest.NewRequest("GET", "/lists", nil))
|
|
||||||
require.Equal(resp.StatusCode, 200)
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".list-preview")), num_lists+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Messages
|
|
||||||
// --------
|
|
||||||
|
|
||||||
// Loading the index page should work if you're logged in
|
|
||||||
func TestMessagesIndexPage(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// Boilerplate for setting an active user
|
|
||||||
app := webserver.NewApp(profile)
|
|
||||||
app.IsScrapingDisabled = true
|
|
||||||
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
|
||||||
|
|
||||||
// Chat list
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/messages", nil))
|
|
||||||
resp := recorder.Result()
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".chat-list .chat-list-entry")), 2)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".chat-view .dm-message")), 0) // No messages until you click on one
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open a chat room
|
|
||||||
func TestMessagesRoom(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// Boilerplate for setting an active user
|
|
||||||
app := webserver.NewApp(profile)
|
|
||||||
app.IsScrapingDisabled = true
|
|
||||||
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
|
||||||
|
|
||||||
// Chat detail
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
app.ServeHTTP(recorder, httptest.NewRequest("GET", "/messages/1488963321701171204-1178839081222115328", nil))
|
|
||||||
resp := recorder.Result()
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".chat-list .chat-list-entry")), 2) // Chat list still renders
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector("#chat-view .dm-message")), 5)
|
|
||||||
|
|
||||||
// Should have the poller at the bottom
|
|
||||||
poller := cascadia.Query(root, selector("#new-messages-poller"))
|
|
||||||
assert.NotNil(poller)
|
|
||||||
assert.Contains(poller.Attr, html.Attribute{Key: "hx-get", Val: "/messages/1488963321701171204-1178839081222115328"})
|
|
||||||
assert.Contains(
|
|
||||||
cascadia.Query(poller, selector("input[name='scroll_bottom']")).Attr,
|
|
||||||
html.Attribute{Key: "value", Val: "1"},
|
|
||||||
)
|
|
||||||
assert.Contains(
|
|
||||||
cascadia.Query(poller, selector("input[name='latest_timestamp']")).Attr,
|
|
||||||
html.Attribute{Key: "value", Val: "1686025129144"},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loading the page since a given message
|
|
||||||
func TestMessagesRoomPollForUpdates(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// Boilerplate for setting an active user
|
|
||||||
app := webserver.NewApp(profile)
|
|
||||||
app.IsScrapingDisabled = true
|
|
||||||
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
|
||||||
|
|
||||||
// Chat detail
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
req := httptest.NewRequest("GET", "/messages/1488963321701171204-1178839081222115328?poll&latest_timestamp=1686025129141", nil)
|
|
||||||
req.Header.Set("HX-Request", "true")
|
|
||||||
app.ServeHTTP(recorder, req)
|
|
||||||
resp := recorder.Result()
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".dm-message")), 3)
|
|
||||||
|
|
||||||
// Should have the poller at the bottom
|
|
||||||
poller := cascadia.Query(root, selector("#new-messages-poller"))
|
|
||||||
assert.NotNil(poller)
|
|
||||||
assert.Contains(poller.Attr, html.Attribute{Key: "hx-get", Val: "/messages/1488963321701171204-1178839081222115328"})
|
|
||||||
assert.Contains(
|
|
||||||
cascadia.Query(poller, selector("input[name='scroll_bottom']")).Attr,
|
|
||||||
html.Attribute{Key: "value", Val: "1"},
|
|
||||||
)
|
|
||||||
assert.Contains(
|
|
||||||
cascadia.Query(poller, selector("input[name='latest_timestamp']")).Attr,
|
|
||||||
html.Attribute{Key: "value", Val: "1686025129144"},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loading the page since latest message (no updates)
|
|
||||||
func TestMessagesRoomPollForUpdatesEmptyResult(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// Boilerplate for setting an active user
|
|
||||||
app := webserver.NewApp(profile)
|
|
||||||
app.IsScrapingDisabled = true
|
|
||||||
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
|
||||||
|
|
||||||
// Chat detail
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
req := httptest.NewRequest("GET", "/messages/1488963321701171204-1178839081222115328?poll&latest_timestamp=1686025129144", nil)
|
|
||||||
req.Header.Set("HX-Request", "true")
|
|
||||||
app.ServeHTTP(recorder, req)
|
|
||||||
resp := recorder.Result()
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".dm-message")), 0)
|
|
||||||
|
|
||||||
// Should have the poller at the bottom, with the same value as previously
|
|
||||||
poller := cascadia.Query(root, selector("#new-messages-poller"))
|
|
||||||
assert.NotNil(poller)
|
|
||||||
assert.Contains(poller.Attr, html.Attribute{Key: "hx-get", Val: "/messages/1488963321701171204-1178839081222115328"})
|
|
||||||
assert.Contains(
|
|
||||||
cascadia.Query(poller, selector("input[name='scroll_bottom']")).Attr,
|
|
||||||
html.Attribute{Key: "value", Val: "1"},
|
|
||||||
)
|
|
||||||
assert.Contains(
|
|
||||||
cascadia.Query(poller, selector("input[name='latest_timestamp']")).Attr,
|
|
||||||
html.Attribute{Key: "value", Val: "1686025129144"},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scroll back in the messages
|
|
||||||
func TestMessagesPaginate(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// Boilerplate for setting an active user
|
|
||||||
app := webserver.NewApp(profile)
|
|
||||||
app.IsScrapingDisabled = true
|
|
||||||
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
|
||||||
|
|
||||||
// Chat detail
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
req := httptest.NewRequest("GET", "/messages/1488963321701171204-1178839081222115328?cursor=1686025129142", nil)
|
|
||||||
req.Header.Set("HX-Request", "true")
|
|
||||||
app.ServeHTTP(recorder, req)
|
|
||||||
resp := recorder.Result()
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".dm-message")), 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNotifications(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
// Boilerplate for setting an active user
|
|
||||||
app := webserver.NewApp(profile)
|
|
||||||
app.IsScrapingDisabled = true
|
|
||||||
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
|
|
||||||
|
|
||||||
// Notifications page
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
req := httptest.NewRequest("GET", "/notifications", nil)
|
|
||||||
app.ServeHTTP(recorder, req)
|
|
||||||
resp := recorder.Result()
|
|
||||||
root, err := html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".notification")), 6)
|
|
||||||
|
|
||||||
// Show more
|
|
||||||
recorder = httptest.NewRecorder()
|
|
||||||
req = httptest.NewRequest("GET", "/notifications?cursor=1726604756351", nil)
|
|
||||||
req.Header.Set("HX-Request", "true")
|
|
||||||
app.ServeHTTP(recorder, req)
|
|
||||||
resp = recorder.Result()
|
|
||||||
root, err = html.Parse(resp.Body)
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Len(cascadia.QueryAll(root, selector(".notification")), 5)
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user